doc-next-gen

Init.Data.List.Nat.TakeDrop

Module docstring

{"# Further lemmas about List.take, List.drop, List.zip and List.zipWith.

These are in a separate file from most of the list lemmas as they required importing more lemmas about natural numbers, and use omega. ","### take ","### drop ","### findIdx ","### findIdx? ","### takeWhile ","### rotateLeft ","### rotateRight ","### zipWith ","### zip "}

List.length_take theorem
: ∀ {i : Nat} {l : List α}, (take i l).length = min i l.length
Full source
@[simp] theorem length_take : ∀ {i : Nat} {l : List α}, (take i l).length = min i l.length
  | 0, l => by simp [Nat.zero_min]
  | succ n, [] => by simp [Nat.min_zero]
  | succ n, _ :: l => by simp [Nat.succ_min_succ, length_take]
Length of Take Equals Minimum of Index and List Length
Informal description
For any natural number $i$ and any list $l$, the length of the list obtained by taking the first $i$ elements of $l$ is equal to the minimum of $i$ and the length of $l$, i.e., $$\text{length}(\text{take}(i, l)) = \min(i, \text{length}(l)).$$
List.length_take_le theorem
(i) (l : List α) : length (take i l) ≤ i
Full source
theorem length_take_le (i) (l : List α) : length (take i l) ≤ i := by simp [Nat.min_le_left]
Upper Bound on Length of Taken List Elements: $\text{length}(\text{take}(i, l)) \leq i$
Informal description
For any natural number $i$ and any list $l$, the length of the list obtained by taking the first $i$ elements of $l$ is less than or equal to $i$, i.e., $$\text{length}(\text{take}(i, l)) \leq i.$$
List.length_take_le' theorem
(i) (l : List α) : length (take i l) ≤ l.length
Full source
theorem length_take_le' (i) (l : List α) : length (take i l) ≤ l.length :=
  by simp [Nat.min_le_right]
Length of Take is Bounded by List Length
Informal description
For any natural number $i$ and any list $l$, the length of the list obtained by taking the first $i$ elements of $l$ is less than or equal to the length of $l$, i.e., $$\text{length}(\text{take}(i, l)) \leq \text{length}(l).$$
List.length_take_of_le theorem
(h : i ≤ length l) : length (take i l) = i
Full source
theorem length_take_of_le (h : i ≤ length l) : length (take i l) = i := by simp [Nat.min_eq_left h]
Length of Take Equals Index When Index Bounded by List Length
Informal description
For any natural number $i$ and any list $l$, if $i$ is less than or equal to the length of $l$, then the length of the list obtained by taking the first $i$ elements of $l$ is equal to $i$, i.e., $$\text{length}(\text{take}(i, l)) = i.$$
List.getElem_take' theorem
{xs : List α} {i j : Nat} (hi : i < xs.length) (hj : i < j) : xs[i] = (xs.take j)[i]'(length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩)
Full source
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the big list to the small list. -/
theorem getElem_take' {xs : List α} {i j : Nat} (hi : i < xs.length) (hj : i < j) :
    xs[i] = (xs.take j)[i]'(length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩) :=
  getElem_of_eq (take_append_drop j xs).symm _ ▸ getElem_append_left ..
Element Preservation in List Prefix: $xs[i] = (\text{take}(j, xs))[i]$ for $i < j$ and $i < \text{length}(xs)$
Informal description
For any list $xs$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i < \text{length}(xs)$ and $i < j$, the $i$-th element of $xs$ is equal to the $i$-th element of the list obtained by taking the first $j$ elements of $xs$. That is, $$xs[i] = (\text{take}(j, xs))[i].$$
List.getElem_take theorem
{xs : List α} {j i : Nat} {h : i < (xs.take j).length} : (xs.take j)[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _))
Full source
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
length `> i`. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_take {xs : List α} {j i : Nat} {h : i < (xs.take j).length} :
    (xs.take j)[i] =
    xs[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
  rw [length_take, Nat.lt_min] at h; rw [getElem_take' (xs := xs) _ h.1]
Element Preservation in List Prefix: $(\text{take}(j, xs))[i] = xs[i]$ for $i < \text{length}(\text{take}(j, xs))$
Informal description
For any list $xs$ of elements of type $\alpha$ and natural numbers $i$ and $j$, if $i$ is less than the length of the list obtained by taking the first $j$ elements of $xs$ (i.e., $i < \text{length}(\text{take}(j, xs))$), then the $i$-th element of $\text{take}(j, xs)$ is equal to the $i$-th element of $xs$. That is, $$(\text{take}(j, xs))[i] = xs[i].$$
List.getElem?_take_eq_none theorem
{l : List α} {i j : Nat} (h : i ≤ j) : (l.take i)[j]? = none
Full source
theorem getElem?_take_eq_none {l : List α} {i j : Nat} (h : i ≤ j) :
    (l.take i)[j]? = none :=
  getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
Optional Indexing Beyond Taken Elements Yields None
Informal description
For any list $l$ of type $\alpha$ and natural numbers $i$ and $j$ such that $i \leq j$, the optional indexing operation $(l.take\ i)[j]?$ returns `none`.
List.getElem?_take theorem
{l : List α} {i j : Nat} : (l.take i)[j]? = if j < i then l[j]? else none
Full source
theorem getElem?_take {l : List α} {i j : Nat} :
    (l.take i)[j]? = if j < i then l[j]? else none := by
  split
  · next h => exact getElem?_take_of_lt h
  · next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
Optional Indexing of List Take: $(l.take\ i)[j]? = \text{if } j < i \text{ then } l[j]? \text{ else none}$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$, the optional indexing operation on the first $i$ elements of $l$ at position $j$ is equal to the optional indexing operation on $l$ at position $j$ if $j < i$, and is `none` otherwise. In other words, $(l.take\ i)[j]? = \begin{cases} l[j]? & \text{if } j < i \\ \text{none} & \text{otherwise.} \end{cases}$
List.head?_take theorem
{l : List α} {i : Nat} : (l.take i).head? = if i = 0 then none else l.head?
Full source
theorem head?_take {l : List α} {i : Nat} :
    (l.take i).head? = if i = 0 then none else l.head? := by
  simp [head?_eq_getElem?, getElem?_take]
  split
  · rw [if_neg (by omega)]
  · rw [if_pos (by omega)]
Optional Head of List Take: $\text{head?}(l.take\ i) = \text{if } i = 0 \text{ then none else head?}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, the optional head of the first $i$ elements of $l$ (i.e., $\text{head?}(l.take\ i)$) is equal to `none` if $i = 0$, and is equal to the optional head of $l$ otherwise (i.e., $\text{head?}(l)$).
List.head_take theorem
{l : List α} {i : Nat} (h : l.take i ≠ []) : (l.take i).head h = l.head (by simp_all)
Full source
theorem head_take {l : List α} {i : Nat} (h : l.take i ≠ []) :
    (l.take i).head h = l.head (by simp_all) := by
  apply Option.some_inj.1
  rw [← head?_eq_head, ← head?_eq_head, head?_take, if_neg]
  simp_all
Head of List Prefix Equals Head of Original List
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, if the list obtained by taking the first $i$ elements of $l$ is non-empty, then the head of this prefix equals the head of the original list $l$.
List.getLast?_take theorem
{l : List α} : (l.take i).getLast? = if i = 0 then none else l[i - 1]?.or l.getLast?
Full source
theorem getLast?_take {l : List α} : (l.take i).getLast? = if i = 0 then none else l[i - 1]?.or l.getLast? := by
  rw [getLast?_eq_getElem?, getElem?_take, length_take]
  split
  · rw [if_neg (by omega)]
    rw [Nat.min_def]
    split
    · rw [getElem?_eq_getElem (by omega)]
      simp
    · rw [← getLast?_eq_getElem?, getElem?_eq_none (by omega)]
      simp
  · rw [if_pos]
    omega
Optional Last Element of List Take: $\text{getLast?}(\text{take}(i, l)) = \text{if } i = 0 \text{ then none else } l[i - 1]? \text{ or } \text{getLast?}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, the optional last element of the list obtained by taking the first $i$ elements of $l$ is equal to: - `none` if $i = 0$, or - the optional element at index $i - 1$ of $l$ if it exists, otherwise the optional last element of $l$. In other words, $\text{getLast?}(\text{take}(i, l)) = \begin{cases} \text{none} & \text{if } i = 0 \\ l[i - 1]? \text{ or } \text{getLast?}(l) & \text{otherwise.} \end{cases}$
List.getLast_take theorem
{l : List α} (h : l.take i ≠ []) : (l.take i).getLast h = l[i - 1]?.getD (l.getLast (by simp_all))
Full source
theorem getLast_take {l : List α} (h : l.take i ≠ []) :
    (l.take i).getLast h = l[i - 1]?.getD (l.getLast (by simp_all)) := by
  rw [getLast_eq_getElem, getElem_take]
  simp [length_take, Nat.min_def]
  simp at h
  split
  · rw [getElem?_eq_getElem (by omega)]
    simp
  · rw [getElem?_eq_none (by omega), getLast_eq_getElem]
    simp
Last Element of List Prefix Equals Indexed or Final Element: $\text{getLast}(\text{take}(i, l)) = l[i-1]?.\text{getD}(\text{getLast}(l))$ for Non-Empty Prefix
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, if the list obtained by taking the first $i$ elements of $l$ is non-empty, then the last element of this prefix is equal to: - The $(i-1)$-th element of $l$ (if it exists), or - The last element of $l$ (if $i-1$ is out of bounds). In other words, if $\text{take}(i, l) \neq []$, then: $$\text{getLast}(\text{take}(i, l), h) = \begin{cases} l[i-1] & \text{if } i-1 < \text{length}(l) \\ \text{getLast}(l) & \text{otherwise} \end{cases}$$
List.take_take theorem
: ∀ {i j} {l : List α}, take i (take j l) = take (min i j) l
Full source
theorem take_take : ∀ {i j} {l : List α}, take i (take j l) = take (min i j) l
  | n, 0, l => by rw [Nat.min_zero, take_zero, take_nil]
  | 0, m, l => by rw [Nat.zero_min, take_zero, take_zero]
  | succ n, succ m, nil => by simp only [take_nil]
  | succ n, succ m, a :: l => by
    simp only [take, succ_min_succ, take_take]
Nested Take Operations Simplify to Minimum Take: $\text{take}\ i\ (\text{take}\ j\ l) = \text{take}\ (\min(i, j))\ l$
Informal description
For any natural numbers $i$ and $j$, and any list $l$ of elements of type $\alpha$, taking the first $i$ elements of the list obtained by taking the first $j$ elements of $l$ is equivalent to taking the first $\min(i, j)$ elements of $l$ directly. In other words, $\text{take}\ i\ (\text{take}\ j\ l) = \text{take}\ (\min(i, j))\ l$.
List.take_set_of_le theorem
{a : α} {i j : Nat} {l : List α} (h : j ≤ i) : (l.set i a).take j = l.take j
Full source
theorem take_set_of_le {a : α} {i j : Nat} {l : List α} (h : j ≤ i) :
    (l.set i a).take j = l.take j :=
  List.ext_getElem? fun i => by
    rw [getElem?_take, getElem?_take]
    split
    · next h' => rw [getElem?_set_ne (by omega)]
    · rfl
Take Operation Commutes with List Replacement When Index is Beyond Take Length: $(l.\text{set}(i, a)).\text{take}(j) = l.\text{take}(j)$ for $j \leq i$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$ with $j \leq i$, and element $a$ of type $\alpha$, taking the first $j$ elements of the list obtained by replacing the element at position $i$ in $l$ with $a$ is equal to taking the first $j$ elements of $l$ directly. In other words, $(l.\text{set}(i, a)).\text{take}(j) = l.\text{take}(j)$.
List.take_set_of_lt abbrev
Full source
@[deprecated take_set_of_le (since := "2025-02-04")]
abbrev take_set_of_lt := @take_set_of_le
Take Operation with List Replacement When Index is Within Take Length: $(l.\text{set}(i, a)).\text{take}(j) = \text{take}\ i\ l ++ [a] ++ \text{take}\ (j - i - 1)\ (\text{drop}\ (i + 1)\ l)$ for $i < j$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$ with $i < j$, and element $a$ of type $\alpha$, taking the first $j$ elements of the list obtained by replacing the element at position $i$ in $l$ with $a$ is equal to taking the first $i$ elements of $l$ followed by $a$ followed by taking the next $j - i - 1$ elements of $l$. In other words, $(l.\text{set}(i, a)).\text{take}(j) = \text{take}\ i\ l ++ [a] ++ \text{take}\ (j - i - 1)\ (\text{drop}\ (i + 1)\ l)$.
List.take_replicate theorem
{a : α} : ∀ {i n : Nat}, take i (replicate n a) = replicate (min i n) a
Full source
@[simp] theorem take_replicate {a : α} : ∀ {i n : Nat}, take i (replicate n a) = replicate (min i n) a
  | n, 0 => by simp [Nat.min_zero]
  | 0, m => by simp [Nat.zero_min]
  | succ n, succ m => by simp [replicate_succ, succ_min_succ, take_replicate]
Take Operation on Replicated List: $\text{take}\ i\ (\text{replicate}\ n\ a) = \text{replicate}\ (\min(i, n))\ a$
Informal description
For any element $a$ of type $\alpha$ and natural numbers $i$ and $n$, taking the first $i$ elements of a list containing $n$ copies of $a$ results in a list containing $\min(i, n)$ copies of $a$. That is, $\text{take}\ i\ (\text{replicate}\ n\ a) = \text{replicate}\ (\min(i, n))\ a$.
List.drop_replicate theorem
{a : α} : ∀ {i n : Nat}, drop i (replicate n a) = replicate (n - i) a
Full source
@[simp] theorem drop_replicate {a : α} : ∀ {i n : Nat}, drop i (replicate n a) = replicate (n - i) a
  | n, 0 => by simp
  | 0, m => by simp
  | succ n, succ m => by simp [replicate_succ, succ_sub_succ, drop_replicate]
Drop Operation on Replicated List: $\text{drop}\ i\ (\text{replicate}\ n\ a) = \text{replicate}\ (n - i)\ a$
Informal description
For any element $a$ of type $\alpha$ and natural numbers $i$ and $n$, dropping the first $i$ elements from a list containing $n$ copies of $a$ results in a list containing $n - i$ copies of $a$. That is, $\text{drop}\ i\ (\text{replicate}\ n\ a) = \text{replicate}\ (n - i)\ a$.
List.take_append_eq_append_take theorem
{l₁ l₂ : List α} {i : Nat} : take i (l₁ ++ l₂) = take i l₁ ++ take (i - l₁.length) l₂
Full source
/-- Taking the first `i` elements in `l₁ ++ l₂` is the same as appending the first `i` elements
of `l₁` to the first `n - l₁.length` elements of `l₂`. -/
theorem take_append_eq_append_take {l₁ l₂ : List α} {i : Nat} :
    take i (l₁ ++ l₂) = take i l₁ ++ take (i - l₁.length) l₂ := by
  induction l₁ generalizing i
  · simp
  · cases i
    · simp [*]
    · simp only [cons_append, take_succ_cons, length_cons, succ_eq_add_one, cons.injEq,
        append_cancel_left_eq, true_and, *]
      congr 1
      omega
Take Operation Distributes Over List Concatenation: $\text{take}\ i\ (l_1 \mathbin{+\kern-0.5em+} l_2) = \text{take}\ i\ l_1 \mathbin{+\kern-0.5em+} \text{take}\ (i - \text{length}(l_1))\ l_2$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number $i$, taking the first $i$ elements of the concatenated list $l_1 \mathbin{+\kern-0.5em+} l_2$ is equal to the concatenation of the first $i$ elements of $l_1$ and the first $i - \text{length}(l_1)$ elements of $l_2$. That is, \[ \text{take}\ i\ (l_1 \mathbin{+\kern-0.5em+} l_2) = \text{take}\ i\ l_1 \mathbin{+\kern-0.5em+} \text{take}\ (i - \text{length}(l_1))\ l_2. \]
List.take_append_of_le_length theorem
{l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) : (l₁ ++ l₂).take i = l₁.take i
Full source
theorem take_append_of_le_length {l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) :
    (l₁ ++ l₂).take i = l₁.take i := by
  simp [take_append_eq_append_take, Nat.sub_eq_zero_of_le h]
Prefix Preservation in List Concatenation When Index Within First List's Length
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number $i$ such that $i \leq \text{length}(l_1)$, taking the first $i$ elements of the concatenated list $l_1 \mathbin{+\kern-0.5em+} l_2$ is equal to taking the first $i$ elements of $l_1$. That is, \[ \text{take}(i, l_1 \mathbin{+\kern-0.5em+} l_2) = \text{take}(i, l_1). \]
List.take_append theorem
{l₁ l₂ : List α} (i : Nat) : take (l₁.length + i) (l₁ ++ l₂) = l₁ ++ take i l₂
Full source
/-- Taking the first `l₁.length + i` elements in `l₁ ++ l₂` is the same as appending the first
`i` elements of `l₂` to `l₁`. -/
theorem take_append {l₁ l₂ : List α} (i : Nat) :
    take (l₁.length + i) (l₁ ++ l₂) = l₁ ++ take i l₂ := by
  rw [take_append_eq_append_take, take_of_length_le (Nat.le_add_right _ _), Nat.add_sub_cancel_left]
Take Operation on Concatenated Lists: $\text{take}(|l_1| + i, l_1 \mathbin{+\kern-0.5em+} l_2) = l_1 \mathbin{+\kern-0.5em+} \text{take}(i, l_2)$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number $i$, taking the first $|l_1| + i$ elements of the concatenated list $l_1 \mathbin{+\kern-0.5em+} l_2$ is equal to the concatenation of $l_1$ with the first $i$ elements of $l_2$. That is, \[ \text{take}(|l_1| + i, l_1 \mathbin{+\kern-0.5em+} l_2) = l_1 \mathbin{+\kern-0.5em+} \text{take}(i, l_2). \]
List.take_eq_take_iff theorem
: ∀ {l : List α} {i j : Nat}, l.take i = l.take j ↔ min i l.length = min j l.length
Full source
@[simp]
theorem take_eq_take_iff :
    ∀ {l : List α} {i j : Nat}, l.take i = l.take j ↔ min i l.length = min j l.length
  | [], i, j => by simp [Nat.min_zero]
  | _ :: xs, 0, 0 => by simp
  | x :: xs, i + 1, 0 => by simp [Nat.zero_min, succ_min_succ]
  | x :: xs, 0, j + 1 => by simp [Nat.zero_min, succ_min_succ]
  | x :: xs, i + 1, j + 1 => by simp [succ_min_succ, take_eq_take_iff]
Equality of List Prefixes via Minimum Lengths
Informal description
For any list $l$ of type $\alpha$ and natural numbers $i$ and $j$, the first $i$ elements of $l$ are equal to the first $j$ elements of $l$ if and only if the minimum of $i$ and the length of $l$ is equal to the minimum of $j$ and the length of $l$. In other words, $\text{take}(i, l) = \text{take}(j, l) \leftrightarrow \min(i, \text{length}(l)) = \min(j, \text{length}(l))$.
List.take_eq_take abbrev
Full source
@[deprecated take_eq_take_iff (since := "2025-02-16")]
abbrev take_eq_take := @take_eq_take_iff
Equality of List Prefixes via Minimum Lengths
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$, the first $i$ elements of $l$ are equal to the first $j$ elements of $l$ if and only if the minimum of $i$ and the length of $l$ is equal to the minimum of $j$ and the length of $l$. In other words, $\text{take}(i, l) = \text{take}(j, l) \leftrightarrow \min(i, \text{length}(l)) = \min(j, \text{length}(l))$.
List.take_add theorem
{l : List α} {i j : Nat} : l.take (i + j) = l.take i ++ (l.drop i).take j
Full source
theorem take_add {l : List α} {i j : Nat} : l.take (i + j) = l.take i ++ (l.drop i).take j := by
  suffices take (i + j) (take i l ++ drop i l) = take i l ++ take j (drop i l) by
    rw [take_append_drop] at this
    assumption
  rw [take_append_eq_append_take, take_of_length_le, append_right_inj]
  · simp only [take_eq_take_iff, length_take, length_drop]
    omega
  apply Nat.le_trans (m := i)
  · apply length_take_le
  · apply Nat.le_add_right
Additive Property of List Take Operation: $\text{take}(i + j, l) = \text{take}(i, l) \mathbin{+\kern-0.5em+} \text{take}(j, \text{drop}(i, l))$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$, taking the first $i + j$ elements of $l$ is equal to concatenating the first $i$ elements of $l$ with the first $j$ elements of the remaining list after dropping the first $i$ elements. That is, \[ \text{take}(i + j, l) = \text{take}(i, l) \mathbin{+\kern-0.5em+} \text{take}(j, \text{drop}(i, l)). \]
List.take_one theorem
{l : List α} : l.take 1 = l.head?.toList
Full source
theorem take_one {l : List α} : l.take 1 = l.head?.toList := by
  induction l <;> simp
First Element as Singleton List Equals Head Option Conversion
Informal description
For any list $l$ of elements of type $\alpha$, taking the first element of $l$ (as a singleton list) is equal to converting the optional head of $l$ to a list. That is, $\text{take}\ 1\ l = \text{toList}(\text{head?}\ l)$.
List.take_eq_append_getElem_of_pos theorem
{i} {l : List α} (h₁ : 0 < i) (h₂ : i < l.length) : l.take i = l.take (i - 1) ++ [l[i - 1]]
Full source
theorem take_eq_append_getElem_of_pos {i} {l : List α} (h₁ : 0 < i) (h₂ : i < l.length) : l.take i = l.take (i - 1) ++ [l[i - 1]] :=
  match i, h₁ with
  | i + 1, _ => take_succ_eq_append_getElem (by omega)
List Reconstruction via Take and Append: $\text{take}(i, l) = \text{take}(i-1, l) +\!\!+ [l[i-1]]$ for $0 < i < \text{length}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and any positive natural number index $i$ such that $i < \text{length}(l)$, the first $i$ elements of $l$ can be obtained by concatenating the first $i-1$ elements of $l$ with the singleton list containing the $(i-1)$-th element of $l$. In other words: \[ \text{take}(i, l) = \text{take}(i-1, l) +\!\!+ [l[i-1]] \]
List.dropLast_take theorem
{i : Nat} {l : List α} (h : i < l.length) : (l.take i).dropLast = l.take (i - 1)
Full source
theorem dropLast_take {i : Nat} {l : List α} (h : i < l.length) :
    (l.take i).dropLast = l.take (i - 1) := by
  simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, Nat.min_eq_left, take_take, sub_le]
DropLast of Take Equals Take of Predecessor: $\text{dropLast}(\text{take}(i, l)) = \text{take}(i-1, l)$ when $i < \text{length}(l)$
Informal description
For any natural number $i$ and any list $l$ of elements of type $\alpha$, if $i$ is less than the length of $l$, then removing the last element of the first $i$ elements of $l$ is equal to taking the first $i-1$ elements of $l$, i.e., \[ \text{dropLast}(\text{take}(i, l)) = \text{take}(i-1, l). \]
List.map_eq_append_split abbrev
Full source
@[deprecated map_eq_append_iff (since := "2024-09-05")] abbrev map_eq_append_split := @map_eq_append_iff
Characterization of List Mapping via Concatenation: $\text{map } f l = L_1 \mathbin{+\kern-1.5ex+} L_2 \leftrightarrow \exists l_1 l_2, l = l_1 \mathbin{+\kern-1.5ex+} l_2 \land \text{map } f l_1 = L_1 \land \text{map } f l_2 = L_2$
Informal description
For any function $f : \alpha \to \beta$ and any list $l : \text{List } \alpha$, the following are equivalent: 1. The mapped list $\text{map } f l$ can be written as a concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ for some lists $L_1, L_2 : \text{List } \beta$. 2. There exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{map } f l_1 = L_1$, and $\text{map } f l_2 = L_2$.
List.take_eq_dropLast theorem
{l : List α} {i : Nat} (h : i + 1 = l.length) : l.take i = l.dropLast
Full source
theorem take_eq_dropLast {l : List α} {i : Nat} (h : i + 1 = l.length) :
    l.take i = l.dropLast := by
  induction l generalizing i with
  | nil => simp
  | cons a as ih =>
    cases i
    · simp_all
    · cases as with
      | nil => simp_all
      | cons b bs =>
        simp only [take_succ_cons, dropLast_cons₂]
        rw [ih]
        simpa using h
Equality of Take and DropLast for Lists: $\text{take}\ i\ l = \text{dropLast}\ l$ when $i + 1 = \text{length}\ l$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$ such that $i + 1$ equals the length of $l$, taking the first $i$ elements of $l$ is equal to removing the last element of $l$, i.e., $\text{take}\ i\ l = \text{dropLast}\ l$.
List.take_prefix_take_left theorem
{l : List α} {i j : Nat} (h : i ≤ j) : take i l <+: take j l
Full source
theorem take_prefix_take_left {l : List α} {i j : Nat} (h : i ≤ j) : taketake i l <+: take j l := by
  rw [isPrefix_iff]
  intro i w
  rw [getElem?_take_of_lt, getElem_take, getElem?_eq_getElem]
  simp only [length_take] at w
  exact Nat.lt_of_lt_of_le (Nat.lt_of_lt_of_le w (Nat.min_le_left _ _)) h
Prefix Preservation under Increasing Take: $\text{take}(i, l) <+: \text{take}(j, l)$ for $i \leq j$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i \leq j$, the list obtained by taking the first $i$ elements of $l$ is a prefix of the list obtained by taking the first $j$ elements of $l$, i.e., $\text{take}(i, l) <+: \text{take}(j, l)$.
List.take_sublist_take_left theorem
{l : List α} {i j : Nat} (h : i ≤ j) : take i l <+ take j l
Full source
theorem take_sublist_take_left {l : List α} {i j : Nat} (h : i ≤ j) : taketake i l <+ take j l :=
  (take_prefix_take_left h).sublist
Sublist Property of Take Operation: $\text{take}(i, l) <+ \text{take}(j, l)$ for $i \leq j$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i \leq j$, the list obtained by taking the first $i$ elements of $l$ is a sublist of the list obtained by taking the first $j$ elements of $l$, i.e., $\text{take}(i, l) <+ \text{take}(j, l)$.
List.take_subset_take_left theorem
(l : List α) {i j : Nat} (h : i ≤ j) : take i l ⊆ take j l
Full source
theorem take_subset_take_left (l : List α) {i j : Nat} (h : i ≤ j) : taketake i l ⊆ take j l :=
  (take_sublist_take_left h).subset
Subset Property of Take Operation: $\text{take}(i, l) \subseteq \text{take}(j, l)$ for $i \leq j$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i \leq j$, the set of elements in the first $i$ elements of $l$ is a subset of the set of elements in the first $j$ elements of $l$, i.e., $\text{take}(i, l) \subseteq \text{take}(j, l)$.
List.lt_length_drop theorem
{xs : List α} {i j : Nat} (h : i + j < xs.length) : j < (xs.drop i).length
Full source
theorem lt_length_drop {xs : List α} {i j : Nat} (h : i + j < xs.length) : j < (xs.drop i).length := by
  have A : i < xs.length := Nat.lt_of_le_of_lt (Nat.le.intro rfl) h
  rw [(take_append_drop i xs).symm] at h
  simpa only [Nat.le_of_lt A, Nat.min_eq_left, Nat.add_lt_add_iff_left, length_take,
    length_append] using h
Index Bound After Dropping Elements: $j < \text{length}(\text{drop}(i, xs))$ when $i + j < \text{length}(xs)$
Informal description
For any list $xs$ of elements of type $\alpha$ and natural numbers $i$ and $j$, if $i + j$ is less than the length of $xs$, then $j$ is less than the length of the list obtained by dropping the first $i$ elements of $xs$.
List.getElem_drop' theorem
{xs : List α} {i j : Nat} (h : i + j < xs.length) : xs[i + j] = (xs.drop i)[j]'(lt_length_drop h)
Full source
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
theorem getElem_drop' {xs : List α} {i j : Nat} (h : i + j < xs.length) :
    xs[i + j] = (xs.drop i)[j]'(lt_length_drop h) := by
  have : i ≤ xs.length := Nat.le_trans (Nat.le_add_right _ _) (Nat.le_of_lt h)
  rw [getElem_of_eq (take_append_drop i xs).symm h, getElem_append_right]
  · simp [Nat.min_eq_left this, Nat.add_sub_cancel_left]
  · simp [Nat.min_eq_left this, Nat.le_add_right]
Element Correspondence After Dropping: $xs[i + j] = (\text{drop}(i, xs))[j]$ when $i + j < \text{length}(xs)$
Informal description
For any list $xs$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i + j < \text{length}(xs)$, the $(i + j)$-th element of $xs$ is equal to the $j$-th element of the list obtained by dropping the first $i$ elements of $xs$. In other words, under the condition $i + j < \text{length}(xs)$, we have: $$xs[i + j] = (\text{drop}(i, xs))[j]$$
List.getElem_drop theorem
{xs : List α} {i : Nat} {j : Nat} {h : j < (xs.drop i).length} : (xs.drop i)[j] = xs[i + j]'(by rw [Nat.add_comm] exact Nat.add_lt_of_lt_sub (length_drop ▸ h))
Full source
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
@[simp] theorem getElem_drop {xs : List α} {i : Nat} {j : Nat} {h : j < (xs.drop i).length} :
    (xs.drop i)[j] = xs[i + j]'(by
      rw [Nat.add_comm]
      exact Nat.add_lt_of_lt_sub (length_drop ▸ h)) := by
  rw [getElem_drop']
Element Correspondence After Dropping: $(\text{drop}(i, xs))[j] = xs[i + j]$ when $j < \text{length}(\text{drop}(i, xs))$
Informal description
For any list $xs$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $j < \text{length}(\text{drop}(i, xs))$, the $j$-th element of the list obtained by dropping the first $i$ elements of $xs$ is equal to the $(i + j)$-th element of $xs$. In other words, under the condition $j < \text{length}(\text{drop}(i, xs))$, we have: $$(\text{drop}(i, xs))[j] = xs[i + j]$$
List.getElem?_drop theorem
{xs : List α} {i j : Nat} : (xs.drop i)[j]? = xs[i + j]?
Full source
@[simp]
theorem getElem?_drop {xs : List α} {i j : Nat} : (xs.drop i)[j]? = xs[i + j]? := by
  ext
  simp only [getElem?_eq_some_iff, getElem_drop, Option.mem_def]
  constructor <;> intro ⟨h, ha⟩
  · exact ⟨_, ha⟩
  · refine ⟨?_, ha⟩
    rw [length_drop]
    rw [Nat.add_comm] at h
    apply Nat.lt_sub_of_add_lt h
Optional Element Correspondence After Dropping: $(\text{drop}(i, xs))[j]? = xs[i + j]?$
Informal description
For any list $xs$ of elements of type $\alpha$ and natural numbers $i$ and $j$, the optional lookup of the $j$-th element in the list obtained by dropping the first $i$ elements of $xs$ is equal to the optional lookup of the $(i + j)$-th element in $xs$. In other words: $$(\text{drop}(i, xs))[j]? = xs[i + j]?$$
List.mem_take_iff_getElem theorem
{l : List α} {a : α} : a ∈ l.take i ↔ ∃ (j : Nat) (hm : j < min i l.length), l[j] = a
Full source
theorem mem_take_iff_getElem {l : List α} {a : α} :
    a ∈ l.take ia ∈ l.take i ↔ ∃ (j : Nat) (hm : j < min i l.length), l[j] = a := by
  rw [mem_iff_getElem]
  constructor
  · rintro ⟨j, hm, rfl⟩
    simp at hm
    refine ⟨j, by omega, by rw [getElem_take]⟩
  · rintro ⟨j, hm, rfl⟩
    refine ⟨j, by simpa, by rw [getElem_take]⟩
Characterization of Membership in List Prefix via Indexing: $a \in \text{take}(i, l) \leftrightarrow \exists j < \min(i, \text{length}(l)), l[j] = a$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the element $a$ appears in the first $i$ elements of $l$ (i.e., $a \in \text{take}(i, l)$) if and only if there exists an index $j$ such that $j < \min(i, \text{length}(l))$ and the $j$-th element of $l$ equals $a$ (i.e., $l[j] = a$).
List.mem_drop_iff_getElem theorem
{l : List α} {a : α} : a ∈ l.drop i ↔ ∃ (j : Nat) (hm : j + i < l.length), l[i + j] = a
Full source
theorem mem_drop_iff_getElem {l : List α} {a : α} :
    a ∈ l.drop ia ∈ l.drop i ↔ ∃ (j : Nat) (hm : j + i < l.length), l[i + j] = a := by
  rw [mem_iff_getElem]
  constructor
  · rintro ⟨i, hm, rfl⟩
    simp at hm
    refine ⟨i, by omega, by rw [getElem_drop]⟩
  · rintro ⟨i, hm, rfl⟩
    refine ⟨i, by simp; omega, by rw [getElem_drop]⟩
Membership in Dropped List via Indexing: $a \in \text{drop}(i, l) \leftrightarrow \exists j, j + i < |l| \text{ and } l[i + j] = a$
Informal description
For any list $l$ of elements of type $\alpha$, any element $a \in \alpha$, and any natural number $i$, the element $a$ belongs to the list obtained by dropping the first $i$ elements of $l$ if and only if there exists a natural number $j$ such that $j + i < \text{length}(l)$ and $l[i + j] = a$. In other words: $$a \in \text{drop}(i, l) \leftrightarrow \exists j \in \mathbb{N}, j + i < |l| \text{ and } l[i + j] = a$$
List.head?_drop theorem
{l : List α} {i : Nat} : (l.drop i).head? = l[i]?
Full source
@[simp] theorem head?_drop {l : List α} {i : Nat} :
    (l.drop i).head? = l[i]? := by
  rw [head?_eq_getElem?, getElem?_drop, Nat.add_zero]
Optional Head of Dropped List Equals Optional Index Access: $\text{head?}(\text{drop}(i, l)) = l[i]?$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, the optional head of the list obtained by dropping the first $i$ elements of $l$ is equal to the optional element at index $i$ of $l$. In other words: $$\text{head?}(\text{drop}(i, l)) = l[i]?$$
List.head_drop theorem
{l : List α} {i : Nat} (h : l.drop i ≠ []) : (l.drop i).head h = l[i]'(by simp_all)
Full source
@[simp] theorem head_drop {l : List α} {i : Nat} (h : l.drop i ≠ []) :
    (l.drop i).head h = l[i]'(by simp_all) := by
  have w : i < l.length := length_lt_of_drop_ne_nil h
  simp [getElem?_eq_getElem, h, w, head_eq_iff_head?_eq_some]
Head of Dropped List Equals Indexed Element: $\text{head}(\text{drop}(i, l)) = l[i]$ when $\text{drop}(i, l) \neq []$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, if the list obtained by dropping the first $i$ elements of $l$ is non-empty, then the head of the resulting list equals the $i$-th element of $l$. In other words: If $\text{drop}(i, l) \neq []$, then $\text{head}(\text{drop}(i, l)) = l[i]$.
List.getLast?_drop theorem
{l : List α} : (l.drop i).getLast? = if l.length ≤ i then none else l.getLast?
Full source
theorem getLast?_drop {l : List α} : (l.drop i).getLast? = if l.length ≤ i then none else l.getLast? := by
  rw [getLast?_eq_getElem?, getElem?_drop]
  rw [length_drop]
  split
  · rw [getElem?_eq_none (by omega)]
  · rw [getLast?_eq_getElem?]
    congr
    omega
Optional Last Element of Dropped List: $\text{getLast?}(\text{drop}(i, l)) = \text{if } |l| \leq i \text{ then none else getLast?}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, the optional last element of the list obtained by dropping the first $i$ elements of $l$ is equal to `none` if the length of $l$ is less than or equal to $i$, and otherwise it is equal to the optional last element of $l$. In other words: $$\text{getLast?}(\text{drop}(i, l)) = \begin{cases} \text{none} & \text{if } |l| \leq i \\ \text{getLast?}(l) & \text{otherwise} \end{cases}$$
List.getLast_drop theorem
{l : List α} (h : l.drop i ≠ []) : (l.drop i).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega))
Full source
@[simp] theorem getLast_drop {l : List α} (h : l.drop i ≠ []) :
    (l.drop i).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega)) := by
  simp only [ne_eq, drop_eq_nil_iff] at h
  apply Option.some_inj.1
  simp only [← getLast?_eq_getLast, getLast?_drop, ite_eq_right_iff]
  omega
Last Element Preservation Under Drop Operation: $\text{getLast}(\text{drop}(i, l)) = \text{getLast}(l)$ when $\text{drop}(i, l) \neq []$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, if the list obtained by dropping the first $i$ elements of $l$ is non-empty, then the last element of the dropped list equals the last element of $l$. In other words: If $\text{drop}(i, l) \neq []$, then $\text{getLast}(\text{drop}(i, l)) = \text{getLast}(l)$.
List.drop_length_cons theorem
{l : List α} (h : l ≠ []) (a : α) : (a :: l).drop l.length = [l.getLast h]
Full source
theorem drop_length_cons {l : List α} (h : l ≠ []) (a : α) :
    (a :: l).drop l.length = [l.getLast h] := by
  induction l generalizing a with
  | nil =>
    cases h rfl
  | cons y l ih =>
    simp only [drop, length]
    by_cases h₁ : l = []
    · simp [h₁]
    rw [getLast_cons h₁]
    exact ih h₁ y
Drop Length of Cons List Yields Last Element
Informal description
For any non-empty list $l$ of type $\text{List}\,\alpha$ and any element $a$ of type $\alpha$, dropping the first $n$ elements from the list $a :: l$, where $n$ is the length of $l$, results in a singleton list containing the last element of $l$. That is, $\text{drop}(\text{length}(l), a :: l) = [\text{getLast}(l, h)]$, where $h$ is a proof that $l$ is non-empty.
List.drop_append_eq_append_drop theorem
{l₁ l₂ : List α} {i : Nat} : drop i (l₁ ++ l₂) = drop i l₁ ++ drop (i - l₁.length) l₂
Full source
/-- Dropping the elements up to `i` in `l₁ ++ l₂` is the same as dropping the elements up to `i`
in `l₁`, dropping the elements up to `i - l₁.length` in `l₂`, and appending them. -/
theorem drop_append_eq_append_drop {l₁ l₂ : List α} {i : Nat} :
    drop i (l₁ ++ l₂) = drop i l₁ ++ drop (i - l₁.length) l₂ := by
  induction l₁ generalizing i
  · simp
  · cases i
    · simp [*]
    · simp only [cons_append, drop_succ_cons, length_cons, succ_eq_add_one, append_cancel_left_eq, *]
      congr 1
      omega
Drop Operation on Concatenated Lists: $\text{drop}\ i\ (l_1 ++ l_2) = \text{drop}\ i\ l_1 ++ \text{drop}\ (i - |l_1|)\ l_2$
Informal description
For any lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number $i$, dropping the first $i$ elements from the concatenated list $l_1 ++ l_2$ is equal to concatenating the result of dropping the first $i$ elements from $l_1$ with the result of dropping the first $i - \text{length}(l_1)$ elements from $l_2$.
List.drop_append_of_le_length theorem
{l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) : (l₁ ++ l₂).drop i = l₁.drop i ++ l₂
Full source
theorem drop_append_of_le_length {l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) :
    (l₁ ++ l₂).drop i = l₁.drop i ++ l₂ := by
  simp [drop_append_eq_append_drop, Nat.sub_eq_zero_of_le h]
Drop-append equality when index ≤ first list's length: $\text{drop}\ i\ (l_1 ++ l_2) = \text{drop}\ i\ l_1 ++ l_2$ for $i \leq |l_1|$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number $i$ such that $i \leq \text{length}(l_1)$, dropping the first $i$ elements from the concatenated list $l_1 ++ l_2$ is equal to the concatenation of the list obtained by dropping the first $i$ elements from $l_1$ with $l_2$.
List.drop_append theorem
{l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂
Full source
/-- Dropping the elements up to `l₁.length + i` in `l₁ + l₂` is the same as dropping the elements
up to `i` in `l₂`. -/
@[simp]
theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂ := by
  rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
    simp [Nat.add_sub_cancel_left, Nat.le_add_right]
Drop Operation on Concatenated Lists: $\text{drop}(|l_1| + i, l_1 +\!+ l_2) = \text{drop}(i, l_2)$
Informal description
For any lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number $i$, dropping the first $|l_1| + i$ elements from the concatenated list $l_1 +\!+ l_2$ is equal to dropping the first $i$ elements from $l_2$.
List.set_eq_take_append_cons_drop theorem
{l : List α} {i : Nat} {a : α} : l.set i a = if i < l.length then l.take i ++ a :: l.drop (i + 1) else l
Full source
theorem set_eq_take_append_cons_drop {l : List α} {i : Nat} {a : α} :
    l.set i a = if i < l.length then l.take i ++ a :: l.drop (i + 1) else l := by
  split <;> rename_i h
  · ext1 j
    by_cases h' : j < i
    · rw [getElem?_append_left (by simp [length_take]; omega), getElem?_set_ne (by omega),
        getElem?_take_of_lt h']
    · by_cases h'' : j = i
      · subst h''
        rw [getElem?_set_self ‹_›, getElem?_append_right, length_take,
          Nat.min_eq_left (by omega), Nat.sub_self, getElem?_cons_zero]
        rw [length_take]
        exact Nat.min_le_left j l.length
      · have h''' : i < j := by omega
        rw [getElem?_set_ne (by omega), getElem?_append_right, length_take,
          Nat.min_eq_left (by omega)]
        · obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_lt h'''
          have p : i + k + 1 - i = k + 1 := by omega
          rw [p]
          rw [getElem?_cons_succ, getElem?_drop]
          congr 1
          omega
        · rw [length_take]
          exact Nat.le_trans (Nat.min_le_left _ _) (by omega)
  · rw [set_eq_of_length_le]
    omega
List Element Replacement as Take-Append-Drop
Informal description
For any list $l$ of elements of type $\alpha$, natural number index $i$, and element $a$ of type $\alpha$, the list obtained by replacing the $i$-th element of $l$ with $a$ is equal to: - the concatenation of the first $i$ elements of $l$ with $a$ followed by the remaining elements of $l$ (dropping the first $i+1$ elements), if $i$ is a valid index (i.e., $i < \text{length}(l)$); - the original list $l$ otherwise. In mathematical notation: $$l[i \mapsto a] = \begin{cases} \text{take}(i, l) +\!+ [a] +\!+ \text{drop}(i+1, l) & \text{if } i < \text{length}(l) \\ l & \text{otherwise} \end{cases}$$
List.drop_set_of_lt theorem
{a : α} {i j : Nat} {l : List α} (hnm : i < j) : drop j (l.set i a) = l.drop j
Full source
theorem drop_set_of_lt {a : α} {i j : Nat} {l : List α} (hnm : i < j) : drop j (l.set i a) = l.drop j :=
  ext_getElem? fun k => by simpa only [getElem?_drop] using getElem?_set_ne (by omega)
Drop Operation Commutes with Element Replacement at Lower Index: $\text{drop}(j, l.\text{set}(i, a)) = \text{drop}(j, l)$ for $i < j$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$ with $i < j$, and element $a$ of type $\alpha$, dropping the first $j$ elements from the list obtained by replacing the $i$-th element of $l$ with $a$ is equal to dropping the first $j$ elements from $l$ itself. In other words: $$\text{drop}(j, l.\text{set}(i, a)) = \text{drop}(j, l)$$
List.drop_take theorem
: ∀ {i j : Nat} {l : List α}, drop i (take j l) = take (j - i) (drop i l)
Full source
theorem drop_take : ∀ {i j : Nat} {l : List α}, drop i (take j l) = take (j - i) (drop i l)
  | 0, _, _ => by simp
  | _, 0, _ => by simp
  | _, _, [] => by simp
  | i+1, j+1, h :: t => by
    simp [take_succ_cons, drop_succ_cons, drop_take]
    congr 1
    omega
Commutativity of List Drop and Take Operations: $\text{drop}\ i \circ \text{take}\ j = \text{take}\ (j-i) \circ \text{drop}\ i$
Informal description
For any natural numbers $i$ and $j$ and any list $l$ of elements of type $\alpha$, dropping the first $i$ elements from the list obtained by taking the first $j$ elements of $l$ is equal to taking the first $j - i$ elements from the list obtained by dropping the first $i$ elements of $l$. In other words: $$\text{drop}\ i\ (\text{take}\ j\ l) = \text{take}\ (j - i)\ (\text{drop}\ i\ l)$$
List.drop_take_self theorem
: drop i (take i l) = []
Full source
@[simp] theorem drop_take_self : drop i (take i l) = [] := by
  rw [drop_take]
  simp
Drop-Take Self Cancellation: $\text{drop}\ i \circ \text{take}\ i = \text{empty list}$
Informal description
For any natural number $i$ and any list $l$ of elements of type $\alpha$, dropping the first $i$ elements from the list obtained by taking the first $i$ elements of $l$ results in the empty list. In other words: $$\text{drop}\ i\ (\text{take}\ i\ l) = []$$
List.take_reverse theorem
{α} {xs : List α} {i : Nat} : xs.reverse.take i = (xs.drop (xs.length - i)).reverse
Full source
theorem take_reverse {α} {xs : List α} {i : Nat} :
    xs.reverse.take i = (xs.drop (xs.length - i)).reverse := by
  by_cases h : i ≤ xs.length
  · induction xs generalizing i <;>
      simp only [reverse_cons, drop, reverse_nil, Nat.zero_sub, length, take_nil]
    next hd tl xs_ih =>
    cases Nat.lt_or_eq_of_le h with
    | inl h' =>
      have h' := Nat.le_of_succ_le_succ h'
      rw [take_append_of_le_length, xs_ih h']
      rw [show tl.length + 1 - i = succ (tl.length - i) from _, drop]
      · rwa [succ_eq_add_one, Nat.sub_add_comm]
      · rwa [length_reverse]
    | inr h' =>
      subst h'
      rw [length, Nat.sub_self, drop]
      suffices tl.length + 1 = (tl.reverse ++ [hd]).length by
        rw [this, take_length, reverse_cons]
      rw [length_append, length_reverse]
      rfl
  · have w : xs.length - i = 0 := by omega
    rw [take_of_length_le, w, drop_zero]
    simp
    omega
Take of Reversed List Equals Reverse of Drop: $\text{take}\ i\ (xs.reverse) = (\text{drop}\ (|xs| - i)\ xs).reverse$
Informal description
For any list $xs$ of elements of type $\alpha$ and any natural number $i$, taking the first $i$ elements of the reversed list $xs.reverse$ is equal to reversing the list obtained by dropping the first $|xs| - i$ elements of $xs$. That is, $$ \text{take}\ i\ (xs.reverse) = (\text{drop}\ (|xs| - i)\ xs).reverse $$
List.drop_reverse theorem
{α} {xs : List α} {i : Nat} : xs.reverse.drop i = (xs.take (xs.length - i)).reverse
Full source
theorem drop_reverse {α} {xs : List α} {i : Nat} :
    xs.reverse.drop i = (xs.take (xs.length - i)).reverse := by
  by_cases h : i ≤ xs.length
  · conv =>
      rhs
      rw [← reverse_reverse xs]
    rw [← reverse_reverse xs] at h
    generalize xs.reverse = xs' at h ⊢
    rw [take_reverse]
    · simp only [length_reverse, reverse_reverse] at *
      congr
      omega
  · have w : xs.length - i = 0 := by omega
    rw [drop_of_length_le, w, take_zero, reverse_nil]
    simp
    omega
Drop of Reversed List Equals Reverse of Take: $\text{drop}\ i\ (xs.reverse) = (\text{take}\ (|xs| - i)\ xs).reverse$
Informal description
For any list $xs$ of elements of type $\alpha$ and any natural number $i$, dropping the first $i$ elements from the reversed list $xs.reverse$ is equal to reversing the list obtained by taking the first $|xs| - i$ elements of $xs$. That is, $$ \text{drop}\ i\ (xs.reverse) = (\text{take}\ (|xs| - i)\ xs).reverse $$
List.reverse_take theorem
{l : List α} {i : Nat} : (l.take i).reverse = l.reverse.drop (l.length - i)
Full source
theorem reverse_take {l : List α} {i : Nat} :
    (l.take i).reverse = l.reverse.drop (l.length - i) := by
  by_cases h : i ≤ l.length
  · rw [drop_reverse]
    congr
    omega
  · have w : l.length - i = 0 := by omega
    rw [w, drop_zero, take_of_length_le]
    omega
Reverse-Take-Drop Identity for Lists: $(l \mathbin{\text{take}} i).\text{reverse} = l.\text{reverse} \mathbin{\text{drop}} (|l| - i)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the reverse of the list obtained by taking the first $i$ elements of $l$ is equal to dropping the first $|l| - i$ elements from the reversed list $l$. That is, $$ (l \mathbin{\text{take}} i).\text{reverse} = l.\text{reverse} \mathbin{\text{drop}} (|l| - i). $$
List.reverse_drop theorem
{l : List α} {i : Nat} : (l.drop i).reverse = l.reverse.take (l.length - i)
Full source
theorem reverse_drop {l : List α} {i : Nat} :
    (l.drop i).reverse = l.reverse.take (l.length - i) := by
  by_cases h : i ≤ l.length
  · rw [take_reverse]
    congr
    omega
  · have w : l.length - i = 0 := by omega
    rw [w, take_zero, drop_of_length_le, reverse_nil]
    omega
Reverse-Drop-Take Identity for Lists: $(l \mathbin{\text{drop}} i).\text{reverse} = l.\text{reverse} \mathbin{\text{take}} (|l| - i)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the reverse of the list obtained by dropping the first $i$ elements of $l$ is equal to taking the first $|l| - i$ elements of the reversed list $l$. That is, $$ (l \mathbin{\text{drop}} i).\text{reverse} = l.\text{reverse} \mathbin{\text{take}} (|l| - i). $$
List.take_add_one theorem
{l : List α} {i : Nat} : l.take (i + 1) = l.take i ++ l[i]?.toList
Full source
theorem take_add_one {l : List α} {i : Nat} :
    l.take (i + 1) = l.take i ++ l[i]?.toList := by
  simp [take_add, take_one]
List Take Decomposition: $\text{take}(i + 1, l) = \text{take}(i, l) \mathbin{+\kern-0.5em+} [l[i]]$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$, taking the first $i + 1$ elements of $l$ is equal to concatenating the first $i$ elements of $l$ with the singleton list containing the $i$-th element (if it exists). That is, \[ \text{take}(i + 1, l) = \text{take}(i, l) \mathbin{+\kern-0.5em+} [l[i]] \] where $[l[i]]$ denotes the singleton list containing the $i$-th element if it exists (or the empty list otherwise).
List.drop_eq_getElem?_toList_append theorem
{l : List α} {i : Nat} : l.drop i = l[i]?.toList ++ l.drop (i + 1)
Full source
theorem drop_eq_getElem?_toList_append {l : List α} {i : Nat} :
    l.drop i = l[i]?.toList ++ l.drop (i + 1) := by
  induction l generalizing i with
  | nil => simp
  | cons hd tl ih =>
    cases i
    · simp
    · simp only [drop_succ_cons, getElem?_cons_succ]
      rw [ih]
List Drop Decomposition: $\text{drop}\ i\ l = [l[i]] \mathbin{+\kern-0.5em+} \text{drop}\ (i+1)\ l$
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$, dropping the first $i$ elements of $l$ is equal to the concatenation of the optional $i$-th element (converted to a singleton list) with the list obtained by dropping the first $i+1$ elements of $l$. In other words: $$\text{drop}\ i\ l = [l[i]] \mathbin{+\kern-0.5em+} \text{drop}\ (i+1)\ l$$ where $[l[i]]$ denotes the singleton list containing the $i$-th element if it exists (or the empty list otherwise).
List.drop_sub_one theorem
{l : List α} {i : Nat} (h : 0 < i) : l.drop (i - 1) = l[i - 1]?.toList ++ l.drop i
Full source
theorem drop_sub_one {l : List α} {i : Nat} (h : 0 < i) :
    l.drop (i - 1) = l[i - 1]?.toList ++ l.drop i := by
  rw [drop_eq_getElem?_toList_append]
  congr
  omega
List Drop Decomposition for Positive Indices: $\text{drop}\ (i-1)\ l = [l[i-1]] \mathbin{+\kern-0.5em+} \text{drop}\ i\ l$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $i$ such that $0 < i$, the list obtained by dropping the first $i-1$ elements of $l$ is equal to the concatenation of the optional $(i-1)$-th element (converted to a singleton list) with the list obtained by dropping the first $i$ elements of $l$. In other words: \[ \text{drop}\ (i-1)\ l = [l[i-1]] \mathbin{+\kern-0.5em+} \text{drop}\ i\ l \] where $[l[i-1]]$ denotes the singleton list containing the $(i-1)$-th element if it exists (or the empty list otherwise).
List.false_of_mem_take_findIdx theorem
{xs : List α} {p : α → Bool} (h : x ∈ xs.take (xs.findIdx p)) : p x = false
Full source
theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs.take (xs.findIdx p)) :
    p x = false := by
  simp only [mem_take_iff_getElem, forall_exists_index] at h
  obtain ⟨i, h, rfl⟩ := h
  exact not_of_lt_findIdx (by omega)
Predicate Fails on Elements Before First Satisfying Index in List
Informal description
For any list $xs$ of elements of type $\alpha$, any predicate $p : \alpha \to \text{Bool}$, and any element $x$ in the prefix of $xs$ taken up to the first index where $p$ holds, the predicate $p$ evaluates to false on $x$. In other words, if $x$ appears in the first $\text{findIdx}_p\ xs$ elements of $xs$, then $p(x) = \text{false}$.
List.findIdx_take theorem
{xs : List α} {i : Nat} {p : α → Bool} : (xs.take i).findIdx p = min i (xs.findIdx p)
Full source
@[simp] theorem findIdx_take {xs : List α} {i : Nat} {p : α → Bool} :
    (xs.take i).findIdx p = min i (xs.findIdx p) := by
  induction xs generalizing i with
  | nil => simp
  | cons x xs ih =>
    cases i
    · simp
    · simp only [take_succ_cons, findIdx_cons, ih, cond_eq_if]
      split
      · simp
      · rw [Nat.add_min_add_right]
Index of First Satisfying Element in Prefix Equals Minimum of Index and Prefix Length
Informal description
For any list $xs$ of elements of type $\alpha$, any natural number $i$, and any predicate $p : \alpha \to \text{Bool}$, the index of the first element in the first $i$ elements of $xs$ that satisfies $p$ is equal to the minimum of $i$ and the index of the first element in the entire list $xs$ that satisfies $p$. In other words: \[ \text{findIdx}_p (\text{take}\ i\ xs) = \min(i, \text{findIdx}_p\ xs) \]
List.min_findIdx_findIdx theorem
{xs : List α} {p q : α → Bool} : min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a)
Full source
@[simp] theorem min_findIdx_findIdx {xs : List α} {p q : α → Bool} :
    min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
  induction xs with
  | nil => simp
  | cons x xs ih =>
    simp [findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
    split <;> split <;> simp_all [Nat.add_min_add_right]
Minimum of First Satisfying Indices Equals First Satisfying Index of Disjunction
Informal description
For any list $xs$ of elements of type $\alpha$ and any predicates $p, q : \alpha \to \text{Bool}$, the minimum of the indices of the first elements in $xs$ satisfying $p$ and $q$ respectively is equal to the index of the first element in $xs$ satisfying the disjunction $p(a) \lor q(a)$. In other words: \[ \min(\text{findIdx}_p\ xs, \text{findIdx}_q\ xs) = \text{findIdx}_{(a \mapsto p(a) \lor q(a))}\ xs \]
List.findIdx?_take theorem
{xs : List α} {i : Nat} {p : α → Bool} : (xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i))
Full source
@[simp] theorem findIdx?_take {xs : List α} {i : Nat} {p : α → Bool} :
    (xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i)) := by
  induction xs generalizing i with
  | nil => simp
  | cons x xs ih =>
    cases i
    · simp
    · simp only [take_succ_cons, findIdx?_cons]
      split
      · simp
      · simp [ih, Option.guard_comp, Option.bind_map]
Index of First Satisfying Element in Prefix: $\text{findIdx?}_p (\text{take}\ i\ xs) = \text{bind}\ (\text{findIdx?}_p\ xs)\ (\text{guard}\ (j < i))$
Informal description
For any list $xs$ of elements of type $\alpha$, any natural number $i$, and any predicate $p : \alpha \to \text{Bool}$, the optional index of the first element in the first $i$ elements of $xs$ that satisfies $p$ is equal to the optional index of the first element in $xs$ that satisfies $p$, if that index is less than $i$, and none otherwise. In other words: \[ \text{findIdx?}_p (\text{take}\ i\ xs) = \text{bind}\ (\text{findIdx?}_p\ xs)\ (\text{guard}\ (\lambda j, j < i)) \]
List.takeWhile_eq_take_findIdx_not theorem
{xs : List α} {p : α → Bool} : takeWhile p xs = take (xs.findIdx (fun a => !p a)) xs
Full source
theorem takeWhile_eq_take_findIdx_not {xs : List α} {p : α → Bool} :
    takeWhile p xs = take (xs.findIdx (fun a => !p a)) xs := by
  induction xs with
  | nil => simp
  | cons x xs ih =>
    simp only [takeWhile_cons, ih, findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
    split <;> simp_all
Equivalence of `takeWhile` and `take` with `findIdx` for Negated Predicate
Informal description
For any list $xs$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the list obtained by taking elements from $xs$ while $p$ holds is equal to taking the first $n$ elements of $xs$, where $n$ is the index of the first element in $xs$ that does not satisfy $p$. In other words: \[ \text{takeWhile } p \, xs = \text{take } (\text{findIdx } (\lambda a \Rightarrow \neg p(a)) \, xs) \, xs \]
List.dropWhile_eq_drop_findIdx_not theorem
{xs : List α} {p : α → Bool} : dropWhile p xs = drop (xs.findIdx (fun a => !p a)) xs
Full source
theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
    dropWhile p xs = drop (xs.findIdx (fun a => !p a)) xs := by
  induction xs with
  | nil => simp
  | cons x xs ih =>
    simp only [dropWhile_cons, ih, findIdx_cons, cond_eq_if, Bool.not_eq_eq_eq_not, Bool.not_true]
    split <;> simp_all
Equivalence of `dropWhile` and `drop` with `findIdx` for Negated Predicate
Informal description
For any list $xs$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the list obtained by dropping the longest prefix of $xs$ where $p$ holds is equal to the list obtained by dropping the first index where $\neg p$ holds from $xs$. That is, \[ \text{dropWhile}\ p\ xs = \text{drop}\ (\text{findIdx}\ (\lambda a, \neg p\ a)\ xs)\ xs. \]
List.rotateLeft_replicate theorem
{n} {a : α} : rotateLeft (replicate m a) n = replicate m a
Full source
@[simp] theorem rotateLeft_replicate {n} {a : α} : rotateLeft (replicate m a) n = replicate m a := by
  cases n with
  | zero => simp
  | succ n =>
    suffices 1 < m → m - (n + 1) % m + min ((n + 1) % m) m = m by
      simpa [rotateLeft]
    intro h
    rw [Nat.min_eq_left (Nat.le_of_lt (Nat.mod_lt _ (by omega)))]
    have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
    omega
Left Rotation Preserves Replicated List: $\text{rotateLeft}(\text{replicate}(m, a), n) = \text{replicate}(m, a)$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, rotating a list consisting of $m$ copies of $a$ left by $n$ positions results in the same list, i.e., $\text{rotateLeft}(\text{replicate}(m, a), n) = \text{replicate}(m, a)$.
List.rotateRight_replicate theorem
{n} {a : α} : rotateRight (replicate m a) n = replicate m a
Full source
@[simp] theorem rotateRight_replicate {n} {a : α} : rotateRight (replicate m a) n = replicate m a := by
  cases n with
  | zero => simp
  | succ n =>
    suffices 1 < m → m - (m - (n + 1) % m) + min (m - (n + 1) % m) m = m by
      simpa [rotateRight]
    intro h
    have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
    rw [Nat.min_eq_left (by omega)]
    omega
Right Rotation Preserves Replicated List: $\text{rotateRight}(\text{replicate}\,m\,a, n) = \text{replicate}\,m\,a$
Informal description
For any natural number $m$, any element $a$ of type $\alpha$, and any natural number $n$, rotating a list consisting of $m$ copies of $a$ to the right by $n$ positions results in the same list, i.e., $\text{rotateRight}(\text{replicate}\,m\,a, n) = \text{replicate}\,m\,a$.
List.length_zipWith theorem
{f : α → β → γ} {l₁ : List α} {l₂ : List β} : length (zipWith f l₁ l₂) = min (length l₁) (length l₂)
Full source
@[simp] theorem length_zipWith {f : α → β → γ} {l₁ : List α} {l₂ : List β} :
    length (zipWith f l₁ l₂) = min (length l₁) (length l₂) := by
  induction l₁ generalizing l₂ <;> cases l₂ <;>
    simp_all [succ_min_succ, Nat.zero_min, Nat.min_zero]
Length of Zipped Lists: $\text{length}(\text{zipWith } f \, l_1 \, l_2) = \min(\text{length}(l_1), \text{length}(l_2))$
Informal description
For any function $f : \alpha \to \beta \to \gamma$ and any lists $l_1$ of type $\text{List } \alpha$ and $l_2$ of type $\text{List } \beta$, the length of the list obtained by applying $f$ pairwise to the elements of $l_1$ and $l_2$ is equal to the minimum of the lengths of $l_1$ and $l_2$, i.e., \[ \text{length}(\text{zipWith } f \, l_1 \, l_2) = \min(\text{length}(l_1), \text{length}(l_2)). \]
List.lt_length_left_of_zipWith theorem
{f : α → β → γ} {i : Nat} {l : List α} {l' : List β} (h : i < (zipWith f l l').length) : i < l.length
Full source
theorem lt_length_left_of_zipWith {f : α → β → γ} {i : Nat} {l : List α} {l' : List β}
    (h : i < (zipWith f l l').length) : i < l.length := by rw [length_zipWith] at h; omega
Index Bound in Left List for ZipWith Operation: $i < \text{length}(\text{zipWith } f \, l \, l') \implies i < \text{length}(l)$
Informal description
For any function $f : \alpha \to \beta \to \gamma$, natural number $i$, and lists $l$ of type $\text{List } \alpha$ and $l'$ of type $\text{List } \beta$, if $i$ is less than the length of the list obtained by applying $f$ pairwise to the elements of $l$ and $l'$, then $i$ is less than the length of $l$. In other words, if $i < \text{length}(\text{zipWith } f \, l \, l')$, then $i < \text{length}(l)$.
List.lt_length_right_of_zipWith theorem
{f : α → β → γ} {i : Nat} {l : List α} {l' : List β} (h : i < (zipWith f l l').length) : i < l'.length
Full source
theorem lt_length_right_of_zipWith {f : α → β → γ} {i : Nat} {l : List α} {l' : List β}
    (h : i < (zipWith f l l').length) : i < l'.length := by rw [length_zipWith] at h; omega
Index Bound in Right List for `zipWith`: $i < \text{length}(\text{zipWith } f \, l \, l') \to i < \text{length}(l')$
Informal description
For any function $f : \alpha \to \beta \to \gamma$, natural number $i$, and lists $l : \text{List } \alpha$, $l' : \text{List } \beta$, if $i$ is less than the length of the list obtained by applying $f$ pairwise to $l$ and $l'$, then $i$ is also less than the length of $l'$. In other words, if $i < \text{length}(\text{zipWith } f \, l \, l')$, then $i < \text{length}(l')$.
List.getElem_zipWith theorem
{f : α → β → γ} {l : List α} {l' : List β} {i : Nat} {h : i < (zipWith f l l').length} : (zipWith f l l')[i] = f (l[i]'(lt_length_left_of_zipWith h)) (l'[i]'(lt_length_right_of_zipWith h))
Full source
@[simp]
theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
    {i : Nat} {h : i < (zipWith f l l').length} :
    (zipWith f l l')[i] =
      f (l[i]'(lt_length_left_of_zipWith h))
        (l'[i]'(lt_length_right_of_zipWith h)) := by
  rw [← Option.some_inj, ← getElem?_eq_getElem, getElem?_zipWith_eq_some]
  exact
    ⟨l[i]'(lt_length_left_of_zipWith h), l'[i]'(lt_length_right_of_zipWith h),
      by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem]; exact ⟨rfl, rfl⟩⟩
Element-wise Characterization of $\text{zipWith}$: $(\text{zipWith}\,f\,l\,l')[i] = f(l[i])(l'[i])$ for valid index $i$
Informal description
For any function $f : \alpha \to \beta \to \gamma$, lists $l$ of type $\text{List}\,\alpha$ and $l'$ of type $\text{List}\,\beta$, and natural number index $i$ such that $i < \text{length}(\text{zipWith}\,f\,l\,l')$, the $i$-th element of $\text{zipWith}\,f\,l\,l'$ is equal to $f$ applied to the $i$-th elements of $l$ and $l'$. That is, \[ (\text{zipWith}\,f\,l\,l')[i] = f(l[i])(l'[i]), \] where $l[i]$ and $l'[i]$ are well-defined because $i < \text{length}(l)$ and $i < \text{length}(l')$ (as guaranteed by the hypotheses $\text{lt\_length\_left\_of\_zipWith}\,h$ and $\text{lt\_length\_right\_of\_zipWith}\,h$).
List.zipWith_eq_zipWith_take_min theorem
: ∀ {l₁ : List α} {l₂ : List β}, zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
Full source
theorem zipWith_eq_zipWith_take_min : ∀ {l₁ : List α} {l₂ : List β},
    zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
  | [], _ => by simp
  | _, [] => by simp
  | a :: l₁, b :: l₂ => by simp [succ_min_succ, zipWith_eq_zipWith_take_min (l₁ := l₁) (l₂ := l₂)]
Equality of `zipWith` and `zipWith` of Truncated Lists: $\text{zipWith } f \, l_1 \, l_2 = \text{zipWith } f \, (\text{take } \min(|l_1|, |l_2|) \, l_1) \, (\text{take } \min(|l_1|, |l_2|) \, l_2)$
Informal description
For any function $f : \alpha \to \beta \to \gamma$ and lists $l_1$ of type $\text{List } \alpha$ and $l_2$ of type $\text{List } \beta$, the pairwise application of $f$ to $l_1$ and $l_2$ is equal to the pairwise application of $f$ to the first $\min(\text{length}(l_1), \text{length}(l_2))$ elements of $l_1$ and $l_2$. That is, \[ \text{zipWith } f \, l_1 \, l_2 = \text{zipWith } f \, (\text{take } (\min(\text{length}(l_1), \text{length}(l_2))) \, l_1) \, (\text{take } (\min(\text{length}(l_1), \text{length}(l_2))) \, l_2). \]
List.reverse_zipWith theorem
(h : l.length = l'.length) : (zipWith f l l').reverse = zipWith f l.reverse l'.reverse
Full source
theorem reverse_zipWith (h : l.length = l'.length) :
    (zipWith f l l').reverse = zipWith f l.reverse l'.reverse := by
  induction l generalizing l' with
  | nil => simp
  | cons hd tl hl =>
    cases l' with
    | nil => simp
    | cons hd' tl' =>
      simp only [Nat.add_right_cancel_iff, length] at h
      have : tl.reverse.length = tl'.reverse.length := by simp [h]
      simp [hl h, zipWith_append this]
Reversing a Zipped List Equals Zipping Reversed Lists under Equal Length Condition
Informal description
For any function $f : \alpha \to \beta \to \gamma$ and lists $l$ of type $\text{List } \alpha$ and $l'$ of type $\text{List } \beta$ such that $\text{length}(l) = \text{length}(l')$, the reverse of the pairwise application of $f$ to $l$ and $l'$ is equal to the pairwise application of $f$ to the reverses of $l$ and $l'$. That is, \[ (\text{zipWith } f \, l \, l').\text{reverse} = \text{zipWith } f \, l.\text{reverse} \, l'.\text{reverse}. \]
List.zipWith_replicate theorem
{a : α} {b : β} {m n : Nat} : zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b)
Full source
@[simp] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
    zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
  rw [zipWith_eq_zipWith_take_min]
  simp
ZipWith of Replicated Lists Yields Replicated Function Application: $\text{zipWith } f \, (\text{replicate } m \, a) \, (\text{replicate } n \, b) = \text{replicate } (\min(m, n)) \, (f \, a \, b)$
Informal description
For any elements $a \in \alpha$, $b \in \beta$, and natural numbers $m, n$, the pairwise application of function $f$ to two lists containing $m$ copies of $a$ and $n$ copies of $b$ respectively yields a list containing $\min(m, n)$ copies of $f(a, b)$. That is, \[ \text{zipWith } f \, (\text{replicate } m \, a) \, (\text{replicate } n \, b) = \text{replicate } (\min(m, n)) \, (f \, a \, b). \]
List.length_zip theorem
{l₁ : List α} {l₂ : List β} : length (zip l₁ l₂) = min (length l₁) (length l₂)
Full source
@[simp] theorem length_zip {l₁ : List α} {l₂ : List β} :
    length (zip l₁ l₂) = min (length l₁) (length l₂) := by
  simp [zip]
Length of Zipped Lists: $\text{length}(\text{zip } l_1 \, l_2) = \min(\text{length}(l_1), \text{length}(l_2))$
Informal description
For any lists $l_1$ of type $\text{List } \alpha$ and $l_2$ of type $\text{List } \beta$, the length of the list obtained by zipping $l_1$ and $l_2$ is equal to the minimum of the lengths of $l_1$ and $l_2$, i.e., \[ \text{length}(\text{zip } l_1 \, l_2) = \min(\text{length}(l_1), \text{length}(l_2)). \]
List.lt_length_left_of_zip theorem
{i : Nat} {l : List α} {l' : List β} (h : i < (zip l l').length) : i < l.length
Full source
theorem lt_length_left_of_zip {i : Nat} {l : List α} {l' : List β} (h : i < (zip l l').length) :
    i < l.length :=
  lt_length_left_of_zipWith h
Index Bound in Left List for Zip Operation: $i < \text{length}(\text{zip } l \, l') \implies i < \text{length}(l)$
Informal description
For any natural number $i$ and lists $l$ of type $\alpha$ and $l'$ of type $\beta$, if $i$ is less than the length of the list obtained by zipping $l$ and $l'$, then $i$ is less than the length of $l$. That is, if $i < \text{length}(\text{zip } l \, l')$, then $i < \text{length}(l)$.
List.lt_length_right_of_zip theorem
{i : Nat} {l : List α} {l' : List β} (h : i < (zip l l').length) : i < l'.length
Full source
theorem lt_length_right_of_zip {i : Nat} {l : List α} {l' : List β} (h : i < (zip l l').length) :
    i < l'.length :=
  lt_length_right_of_zipWith h
Index Bound in Right List for Zip: $i < \text{length}(\text{zip } l \, l') \to i < \text{length}(l')$
Informal description
For any natural number $i$ and lists $l : \text{List } \alpha$, $l' : \text{List } \beta$, if $i$ is less than the length of the list obtained by zipping $l$ and $l'$, then $i$ is also less than the length of $l'$. In other words, if $i < \text{length}(\text{zip } l \, l')$, then $i < \text{length}(l')$.
List.getElem_zip theorem
{l : List α} {l' : List β} {i : Nat} {h : i < (zip l l').length} : (zip l l')[i] = (l[i]'(lt_length_left_of_zip h), l'[i]'(lt_length_right_of_zip h))
Full source
@[simp]
theorem getElem_zip {l : List α} {l' : List β} {i : Nat} {h : i < (zip l l').length} :
    (zip l l')[i] =
      (l[i]'(lt_length_left_of_zip h), l'[i]'(lt_length_right_of_zip h)) :=
  getElem_zipWith (h := h)
Element-wise Characterization of Zip: $(\text{zip}\,l\,l')[i] = (l[i], l'[i])$ for valid index $i$
Informal description
For any lists $l$ of type $\alpha$ and $l'$ of type $\beta$, and any natural number index $i$ such that $i < \text{length}(\text{zip}(l, l'))$, the $i$-th element of $\text{zip}(l, l')$ is equal to the pair $(l[i], l'[i])$.
List.zip_eq_zip_take_min theorem
: ∀ {l₁ : List α} {l₂ : List β}, zip l₁ l₂ = zip (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
Full source
theorem zip_eq_zip_take_min : ∀ {l₁ : List α} {l₂ : List β},
    zip l₁ l₂ = zip (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
  | [], _ => by simp
  | _, [] => by simp
  | a :: l₁, b :: l₂ => by simp [succ_min_succ, zip_eq_zip_take_min (l₁ := l₁) (l₂ := l₂)]
Zip Equals Zip of Minimum-Length Takes
Informal description
For any two lists $l_1$ of type $\alpha$ and $l_2$ of type $\beta$, the pairwise combination $\text{zip}(l_1, l_2)$ is equal to the pairwise combination of the first $\min(\text{length}(l_1), \text{length}(l_2))$ elements of $l_1$ and $l_2$. That is, \[ \text{zip}(l_1, l_2) = \text{zip}(\text{take}(\min(|l_1|, |l_2|), l_1), \text{take}(\min(|l_1|, |l_2|), l_2)). \]
List.zip_replicate theorem
{a : α} {b : β} {m n : Nat} : zip (replicate m a) (replicate n b) = replicate (min m n) (a, b)
Full source
@[simp] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
    zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
  rw [zip_eq_zip_take_min]
  simp
Zip of Replicated Lists: $\text{zip}(\text{replicate}(m, a), \text{replicate}(n, b)) = \text{replicate}(\min(m, n), (a, b))$
Informal description
For any elements $a$ of type $\alpha$ and $b$ of type $\beta$, and any natural numbers $m$ and $n$, the zip of the list containing $m$ copies of $a$ with the list containing $n$ copies of $b$ is equal to the list containing $\min(m, n)$ copies of the pair $(a, b)$. That is, \[ \text{zip}(\text{replicate}(m, a), \text{replicate}(n, b)) = \text{replicate}(\min(m, n), (a, b)). \]