Theorem: Array.ext
File: src/lean/Init/Data/Array/Basic.lean

tactic: let rec extAux (a b : List α)
    (h₁ : a.length = b.length)
    (h₂ : (i : Nat) → (hi₁ : i < a.length) → (hi₂ : i < b.length) → a.get ⟨i, hi₁⟩ = b.get ⟨i, hi₂⟩)
    : a = b := by
  induction a generalizing b with
  | nil =>
    cases b with
    | nil       => rfl
    | cons b bs => rw [List.length_cons] at h₁; injection h₁
  | cons a as ih =>
    cases b with
    | nil => rw [List.length_cons] at h₁; injection h₁
    | cons b bs =>
      have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
      have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
      have headEq : a = b := h₂ 0 hz₁ hz₂
      have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
      have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as.get ⟨i, hi₁⟩ = bs.get ⟨i, hi₂⟩ := by
        intro i hi₁ hi₂
        have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
        have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
        have : (a::as).get ⟨i+1, hi₁'⟩ = (b::bs).get ⟨i+1, hi₂'⟩ := h₂ (i+1) hi₁' hi₂'
        apply this
      have tailEq : as = bs := ih bs h₁' h₂'
      rw [headEq, tailEq]
state_before: α : Type u_1
a b : Array α
h₁ : size a = size b
h₂ : ∀ (i : Nat) (hi₁ : i < size a) (hi₂ : i < size b), getElem a i hi₁ = getElem b i hi₂
⊢ a = b

tactic: cases a
state_before: α : Type u_1
a b : Array α
h₁ : size a = size b
h₂ : ∀ (i : Nat) (hi₁ : i < size a) (hi₂ : i < size b), getElem a i hi₁ = getElem b i hi₂
⊢ a = b

tactic: cases b
state_before: case mk
α : Type u_1
b : Array α
data✝ : List α
h₁ : size { data := data✝ } = size b
h₂ :
  ∀ (i : Nat) (hi₁ : i < size { data := data✝ }) (hi₂ : i < size b), getElem { data := data✝ } i hi₁ = getElem b i hi₂
⊢ { data := data✝ } = b

tactic: apply congrArg
state_before: case mk.mk
α : Type u_1
data✝¹ data✝ : List α
h₁ : size { data := data✝¹ } = size { data := data✝ }
h₂ :
  ∀ (i : Nat) (hi₁ : i < size { data := data✝¹ }) (hi₂ : i < size { data := data✝ }),
    getElem { data := data✝¹ } i hi₁ = getElem { data := data✝ } i hi₂
⊢ { data := data✝¹ } = { data := data✝ }

tactic: apply extAux
state_before: case mk.mk.h
α : Type u_1
data✝¹ data✝ : List α
h₁ : size { data := data✝¹ } = size { data := data✝ }
h₂ :
  ∀ (i : Nat) (hi₁ : i < size { data := data✝¹ }) (hi₂ : i < size { data := data✝ }),
    getElem { data := data✝¹ } i hi₁ = getElem { data := data✝ } i hi₂
⊢ data✝¹ = data✝

tactic: assumption
state_before: case mk.mk.h.h₁
α : Type u_1
data✝¹ data✝ : List α
h₁ : size { data := data✝¹ } = size { data := data✝ }
h₂ :
  ∀ (i : Nat) (hi₁ : i < size { data := data✝¹ }) (hi₂ : i < size { data := data✝ }),
    getElem { data := data✝¹ } i hi₁ = getElem { data := data✝ } i hi₂
⊢ List.length data✝¹ = List.length data✝

case mk.mk.h.h₂
α : Type u_1
data✝¹ data✝ : List α
h₁ : size { data := data✝¹ } = size { data := data✝ }
h₂ :
  ∀ (i : Nat) (hi₁ : i < size { data := data✝¹ }) (hi₂ : i < size { data := data✝ }),
    getElem { data := data✝¹ } i hi₁ = getElem { data := data✝ } i hi₂
⊢ ∀ (i : Nat) (hi₁ : i < List.length data✝¹) (hi₂ : i < List.length data✝),
    List.get data✝¹ { val := i, isLt := hi₁ } = List.get data✝ { val := i, isLt := hi₂ }

tactic: assumption
state_before: case mk.mk.h.h₂
α : Type u_1
data✝¹ data✝ : List α
h₁ : size { data := data✝¹ } = size { data := data✝ }
h₂ :
  ∀ (i : Nat) (hi₁ : i < size { data := data✝¹ }) (hi₂ : i < size { data := data✝ }),
    getElem { data := data✝¹ } i hi₁ = getElem { data := data✝ } i hi₂
⊢ ∀ (i : Nat) (hi₁ : i < List.length data✝¹) (hi₂ : i < List.length data✝),
    List.get data✝¹ { val := i, isLt := hi₁ } = List.get data✝ { val := i, isLt := hi₂ }

tactic: induction a generalizing b with
| nil =>
  cases b with
  | nil       => rfl
  | cons b bs => rw [List.length_cons] at h₁; injection h₁
| cons a as ih =>
  cases b with
  | nil => rw [List.length_cons] at h₁; injection h₁
  | cons b bs =>
    have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
    have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
    have headEq : a = b := h₂ 0 hz₁ hz₂
    have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
    have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as.get ⟨i, hi₁⟩ = bs.get ⟨i, hi₂⟩ := by
      intro i hi₁ hi₂
      have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
      have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
      have : (a::as).get ⟨i+1, hi₁'⟩ = (b::bs).get ⟨i+1, hi₂'⟩ := h₂ (i+1) hi₁' hi₂'
      apply this
    have tailEq : as = bs := ih bs h₁' h₂'
    rw [headEq, tailEq]
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a b : List α
h₁ : List.length a = List.length b
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length a) (hi₂ : i < List.length b),
    List.get a { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }
⊢ a = b

tactic: cases b with
| nil       => rfl
| cons b bs => rw [List.length_cons] at h₁; injection h₁
state_before: case nil
α : Type u_1
a b✝ : Array α
h₁✝ : size a = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a) (hi₂ : i < size b✝), getElem a i hi₁ = getElem b✝ i hi₂
b : List α
h₁ : List.length List.nil = List.length b
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length List.nil) (hi₂ : i < List.length b),
    List.get List.nil { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }
⊢ List.nil = b

tactic: rfl
state_before: case nil.nil
α : Type u_1
a b : Array α
h₁✝ : size a = size b
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a) (hi₂ : i < size b), getElem a i hi₁ = getElem b i hi₂
h₁ : List.length List.nil = List.length List.nil
h₂ :
  ∀ (i : Nat) (hi₁ hi₂ : i < List.length List.nil),
    List.get List.nil { val := i, isLt := hi₁ } = List.get List.nil { val := i, isLt := hi₂ }
⊢ List.nil = List.nil

tactic: rw [List.length_cons] at h₁
state_before: case nil.cons
α : Type u_1
a b✝ : Array α
h₁✝ : size a = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a) (hi₂ : i < size b✝), getElem a i hi₁ = getElem b✝ i hi₂
b : α
bs : List α
h₁ : List.length List.nil = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length List.nil) (hi₂ : i < List.length (b :: bs)),
    List.get List.nil { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
⊢ List.nil = b :: bs

tactic: injection h₁
state_before: case nil.cons
α : Type u_1
a b✝ : Array α
h₁✝ : size a = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a) (hi₂ : i < size b✝), getElem a i hi₁ = getElem b✝ i hi₂
b : α
bs : List α
h₁ : List.length List.nil = Nat.succ (List.length bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length List.nil) (hi₂ : i < List.length (b :: bs)),
    List.get List.nil { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
⊢ List.nil = b :: bs

tactic: cases b with
| nil => rw [List.length_cons] at h₁; injection h₁
| cons b bs =>
  have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
  have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
  have headEq : a = b := h₂ 0 hz₁ hz₂
  have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
  have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as.get ⟨i, hi₁⟩ = bs.get ⟨i, hi₂⟩ := by
    intro i hi₁ hi₂
    have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
    have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
    have : (a::as).get ⟨i+1, hi₁'⟩ = (b::bs).get ⟨i+1, hi₂'⟩ := h₂ (i+1) hi₁' hi₂'
    apply this
  have tailEq : as = bs := ih bs h₁' h₂'
  rw [headEq, tailEq]
state_before: case cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : List α
h₁ : List.length (a :: as) = List.length b
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length b),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }
⊢ a :: as = b

tactic: rw [List.length_cons] at h₁
state_before: case cons.nil
α : Type u_1
a✝ b : Array α
h₁✝ : size a✝ = size b
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b), getElem a✝ i hi₁ = getElem b i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
h₁ : List.length (a :: as) = List.length List.nil
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length List.nil),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get List.nil { val := i, isLt := hi₂ }
⊢ a :: as = List.nil

tactic: injection h₁
state_before: case cons.nil
α : Type u_1
a✝ b : Array α
h₁✝ : size a✝ = size b
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b), getElem a✝ i hi₁ = getElem b i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
h₁ : Nat.succ (List.length as) = List.length List.nil
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length List.nil),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get List.nil { val := i, isLt := hi₂ }
⊢ a :: as = List.nil

tactic: have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
⊢ a :: as = b :: bs

tactic: have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
⊢ a :: as = b :: bs

tactic: have headEq : a = b := h₂ 0 hz₁ hz₂
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
⊢ a :: as = b :: bs

tactic: have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
⊢ a :: as = b :: bs

tactic: have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as.get ⟨i, hi₁⟩ = bs.get ⟨i, hi₂⟩ := by
  intro i hi₁ hi₂
  have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
  have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
  have : (a::as).get ⟨i+1, hi₁'⟩ = (b::bs).get ⟨i+1, hi₂'⟩ := h₂ (i+1) hi₁' hi₂'
  apply this
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
⊢ a :: as = b :: bs

tactic: have tailEq : as = bs := ih bs h₁' h₂'
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
h₂' :
  ∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length bs),
    List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }
⊢ a :: as = b :: bs

tactic: rw [headEq, tailEq]
state_before: case cons.cons
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
h₂' :
  ∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length bs),
    List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }
tailEq : as = bs
⊢ a :: as = b :: bs

tactic: rw [List.length_cons]
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
⊢ 0 < List.length (a :: as)

tactic: apply Nat.zero_lt_succ
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
⊢ 0 < Nat.succ (List.length as)

tactic: rw [List.length_cons]
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
⊢ 0 < List.length (b :: bs)

tactic: apply Nat.zero_lt_succ
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
⊢ 0 < Nat.succ (List.length bs)

tactic: rw [List.length_cons, List.length_cons] at h₁
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
⊢ List.length as = List.length bs

tactic: injection h₁
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : Nat.succ (List.length as) = Nat.succ (List.length bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
⊢ List.length as = List.length bs

tactic: intro i hi₁ hi₂
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
⊢ ∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length bs),
    List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }

tactic: have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
⊢ List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }

tactic: have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
hi₁' : i + 1 < List.length (a :: as)
⊢ List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }

tactic: have : (a::as).get ⟨i+1, hi₁'⟩ = (b::bs).get ⟨i+1, hi₂'⟩ := h₂ (i+1) hi₁' hi₂'
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
hi₁' : i + 1 < List.length (a :: as)
hi₂' : i + 1 < List.length (b :: bs)
⊢ List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }

tactic: apply this
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
hi₁' : i + 1 < List.length (a :: as)
hi₂' : i + 1 < List.length (b :: bs)
this : List.get (a :: as) { val := i + 1, isLt := hi₁' } = List.get (b :: bs) { val := i + 1, isLt := hi₂' }
⊢ List.get as { val := i, isLt := hi₁ } = List.get bs { val := i, isLt := hi₂ }

tactic: rw [List.length_cons]
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
⊢ i + 1 < List.length (a :: as)

tactic: apply Nat.succ_lt_succ
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
⊢ i + 1 < Nat.succ (List.length as)

tactic: assumption
state_before: case a
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
⊢ i < List.length as

tactic: rw [List.length_cons]
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
hi₁' : i + 1 < List.length (a :: as)
⊢ i + 1 < List.length (b :: bs)

tactic: apply Nat.succ_lt_succ
state_before: α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
hi₁' : i + 1 < List.length (a :: as)
⊢ i + 1 < Nat.succ (List.length bs)

tactic: assumption
state_before: case a
α : Type u_1
a✝ b✝ : Array α
h₁✝ : size a✝ = size b✝
h₂✝ : ∀ (i : Nat) (hi₁ : i < size a✝) (hi₂ : i < size b✝), getElem a✝ i hi₁ = getElem b✝ i hi₂
a : α
as : List α
ih :
  ∀ (b : List α),
    List.length as = List.length b →
      (∀ (i : Nat) (hi₁ : i < List.length as) (hi₂ : i < List.length b),
          List.get as { val := i, isLt := hi₁ } = List.get b { val := i, isLt := hi₂ }) →
        as = b
b : α
bs : List α
h₁ : List.length (a :: as) = List.length (b :: bs)
h₂ :
  ∀ (i : Nat) (hi₁ : i < List.length (a :: as)) (hi₂ : i < List.length (b :: bs)),
    List.get (a :: as) { val := i, isLt := hi₁ } = List.get (b :: bs) { val := i, isLt := hi₂ }
hz₁ : 0 < List.length (a :: as)
hz₂ : 0 < List.length (b :: bs)
headEq : a = b
h₁' : List.length as = List.length bs
i : Nat
hi₁ : i < List.length as
hi₂ : i < List.length bs
hi₁' : i + 1 < List.length (a :: as)
⊢ i < List.length bs