-- Mathlib/.lake/packages/lean4/src/lean/Init/Data/Array/Lemmas.lean
theorem toList_reverse (a : Array α) : a.reverse.toList = a.toList.reverse

Proof state:
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
⊢ (reverse.loop as i ⟨j, hj⟩).toList[k]? = a.toList.reverse[k]?

Tactic:
rw [reverse.loop]

Result:
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
⊢ (if h : i < ↑⟨j, hj⟩ then
          let_fun this := ⋯;
          let as_1 := as.swap i ↑⟨j, hj⟩ ⋯ ⋯;
          let_fun this := ⋯;
          reverse.loop as_1 (i + 1) ⟨↑⟨j, hj⟩ - 1, this⟩
        else as).toList[k]? =
    a.toList.reverse[k]?

Proof state:
case isFalse.isFalse
α : Type u_1
a : Array α
h✝ : ¬a.size ≤ 1
this : a.size - 1 + 1 = a.size
k : Nat
h : a.size ≤ k
⊢ a.toList[k]? = a.toList.reverse[k]?

Tactic:
rw [List.getElem?_eq_none_iff.2 ‹_›, List.getElem?_eq_none_iff.2 (a.toList.length_reverse ▸ ‹_›)]

Result:
no goals

Proof state:
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
⊢ (if h : i < ↑⟨j, hj⟩ then
          let_fun this := ⋯;
          let as_1 := as.swap i ↑⟨j, hj⟩ ⋯ ⋯;
          let_fun this := ⋯;
          reverse.loop as_1 (i + 1) ⟨↑⟨j, hj⟩ - 1, this⟩
        else as).toList[k]? =
    a.toList.reverse[k]?

Tactic:
dsimp only

Result:
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
⊢ (if h : i < j then reverse.loop (as.swap i j ⋯ ⋯) (i + 1) ⟨j - 1, ⋯⟩ else as).toList[k]? = a.toList.reverse[k]?

Proof state:
case isFalse.isTrue
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂✝ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
h₁ : ¬i < j
h₂ : i ≤ k ∧ k ≤ j
⊢ a.toList[k]? = a.toList.reverse[k]?

Tactic:
cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)

Result:
case isFalse.isTrue.refl
α : Type u_1
a as : Array α
i : Nat
h₂✝ : as.size = a.size
k : Nat
hj : i < as.size
h : i + i + 1 = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ i then a.toList[k]? else a.toList.reverse[k]?
h₁ : ¬i < i
h₂ : i ≤ k ∧ k ≤ i
⊢ a.toList[k]? = a.toList.reverse[k]?

Proof state:
case isTrue.H.isTrue
α : Type u_1
a as : Array α
i j✝ : Nat
h₂✝ : as.size = a.size
k✝ j : Nat
hj : j + 1 < as.size
h : i + (j + 1) + 1 = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?
h₁ : i < j + 1
k : Nat
h₂ : j + 1 = k
⊢ (if i ≤ i ∧ True then a.toList[i]? else a.toList.reverse[i]?) =
    if i + 1 ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?

Tactic:
simp only [← h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]

Result:
case isTrue.H.isTrue
α : Type u_1
a as : Array α
i j✝ : Nat
h₂✝ : as.size = a.size
k✝ j : Nat
hj : j + 1 < as.size
h : i + (j + 1) + 1 = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?
h₁ : i < j + 1
k : Nat
h₂ : j + 1 = k
⊢ (if True ∧ True then a.toList[i]? else a.toList.reverse[i]?) =
    if False then a.toList[j + 1]? else a.toList.reverse[j + 1]?

Proof state:
case isFalse
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
h₁ : ¬i < j
⊢ as.toList[k]? = a.toList.reverse[k]?

Tactic:
rw [H]

Result:
case isFalse
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
h₁ : ¬i < j
⊢ (if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?) = a.toList.reverse[k]?

Proof state:
case isFalse.isTrue
α : Type u_1
a : Array α
h✝¹ : ¬a.size ≤ 1
this : a.size - 1 + 1 = a.size
k : Nat
h✝ : 0 ≤ k ∧ k ≤ a.size - 1
⊢ a.toList[k]? = a.toList[k]?

Tactic:
rfl

Result:
no goals

Proof state:
case isTrue.H
α : Type u_1
a as : Array α
i j✝ : Nat
h₂ : as.size = a.size
k✝ j : Nat
hj : j + 1 < as.size
h : i + (j + 1) + 1 = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?
h₁ : i < j + 1
k : Nat
⊢ (if j + 1 = k then if i ≤ i ∧ True then a.toList[i]? else a.toList.reverse[i]?
    else
      if i = k then if True ∧ j + 1 ≤ j + 1 then a.toList[j + 1]? else a.toList.reverse[j + 1]?
      else if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?) =
    if i + 1 ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?

Tactic:
split <;> rename_i h₂

Result:
case isTrue.H.isTrue
α : Type u_1
a as : Array α
i j✝ : Nat
h₂✝ : as.size = a.size
k✝ j : Nat
hj : j + 1 < as.size
h : i + (j + 1) + 1 = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?
h₁ : i < j + 1
k : Nat
h₂ : j + 1 = k
⊢ (if i ≤ i ∧ True then a.toList[i]? else a.toList.reverse[i]?) =
    if i + 1 ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?

case isTrue.H.isFalse
α : Type u_1
a as : Array α
i j✝ : Nat
h₂✝ : as.size = a.size
k✝ j : Nat
hj : j + 1 < as.size
h : i + (j + 1) + 1 = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?
h₁ : i < j + 1
k : Nat
h₂ : ¬j + 1 = k
⊢ (if i = k then if True ∧ j + 1 ≤ j + 1 then a.toList[j + 1]? else a.toList.reverse[j + 1]?
    else if i ≤ k ∧ k ≤ j + 1 then a.toList[k]? else a.toList.reverse[k]?) =
    if i + 1 ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?

Proof state:
case isFalse
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
h₁ : ¬i < j
⊢ (if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?) = a.toList.reverse[k]?

Tactic:
split <;> rename_i h₂

Result:
case isFalse.isTrue
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂✝ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
h₁ : ¬i < j
h₂ : i ≤ k ∧ k ≤ j
⊢ a.toList[k]? = a.toList.reverse[k]?

case isFalse.isFalse
α : Type u_1
a as : Array α
i j : Nat
hj : j < as.size
h : i + j + 1 = a.size
h₂✝ : as.size = a.size
H : ∀ (k : Nat), as.toList[k]? = if i ≤ k ∧ k ≤ j then a.toList[k]? else a.toList.reverse[k]?
k : Nat
h₁ : ¬i < j
h₂ : ¬(i ≤ k ∧ k ≤ j)
⊢ a.toList.reverse[k]? = a.toList.reverse[k]?