l3lab/ntp-mathlib huggingface dataset:
/-- Updating a tuple and adding an element at the end commute. -/
@[simp]
theorem snoc_update : snoc (update p i y) x = update (snoc p x) (castSucc i) y := by
  ext j
  by_cases h : j.val < n
  · rw [snoc]
    simp only [h]
    simp only [dif_pos]
    by_cases h' : j = castSucc i
    · have C1 : α (castSucc i) = α j := by rw [h']
      have E1 : update (snoc p x) (castSucc i) y j = _root_.cast C1 y := by
        have : update (snoc p x) j (_root_.cast C1 y) j = _root_.cast C1 y := by simp
        convert this
        · exact h'.symm
        · exact heq_of_cast_eq (congr_arg α (Eq.symm h')) rfl
      have C2 : α (castSucc i) = α (castSucc (castLT j h)) := by rw [castSucc_castLT, h']
      have E2 : update p i y (castLT j h) = _root_.cast C2 y := by
        have : update p (castLT j h) (_root_.cast C2 y) (castLT j h) = _root_.cast C2 y := by simp
        convert this
        · simp [h, h']
        · exact heq_of_cast_eq C2 rfl
      rw [E1, E2]
      exact eq_rec_compose (Eq.trans C2.symm C1) C2 y
    · have : ¬castLT j h = i := by
        intro E
        apply h'
        rw [← E, castSucc_castLT]
      simp [h', this, snoc, h]
  · rw [eq_last_of_not_lt h]
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ¬↑j < n
⊢ snoc (update p i y) x (last n) = update (snoc p x) (castSucc i) y (last n)

Next tactic:
simp [Ne.symm (ne_of_lt (castSucc_lt_last i))]
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
⊢ update (snoc p x) (last n) z = snoc p z

Next tactic:
ext j
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by
  ext j
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
⊢ update (snoc p x) (last n) z j = snoc p z j

Next tactic:
by_cases h : j.val < n
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by
  ext j
  by_cases h : j.val < n
  · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ↑j < n
⊢ update (snoc p x) (last n) z j = snoc p z j

Next tactic:
have : j ≠ last n := ne_of_lt h
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by
  ext j
  by_cases h : j.val < n
  · have : j ≠ last n := ne_of_lt h
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ↑j < n
this : j ≠ last n
⊢ update (snoc p x) (last n) z j = snoc p z j

Next tactic:
simp [h, update_noteq, this, snoc]
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by
  ext j
  by_cases h : j.val < n
  · have : j ≠ last n := ne_of_lt h
    simp [h, update_noteq, this, snoc]
  · 

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ¬↑j < n
⊢ update (snoc p x) (last n) z j = snoc p z j

Next tactic:
rw [eq_last_of_not_lt h]
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z := by
  ext j
  by_cases h : j.val < n
  · have : j ≠ last n := ne_of_lt h
    simp [h, update_noteq, this, snoc]
  · rw [eq_last_of_not_lt h]
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ¬↑j < n
⊢ update (snoc p x) (last n) z (last n) = snoc p z (last n)

Next tactic:
simp
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
⊢ snoc (init q) (q (last n)) = q

Next tactic:
ext j
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
⊢ snoc (init q) (q (last n)) j = q j

Next tactic:
by_cases h : j.val < n
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  by_cases h : j.val < n
  · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ↑j < n
⊢ snoc (init q) (q (last n)) j = q j

Next tactic:
simp only [init, snoc, h, cast_eq, dite_true]
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  by_cases h : j.val < n
  · simp only [init, snoc, h, cast_eq, dite_true]
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ↑j < n
⊢ q (castSucc (castLT j (_ : ↑j < n))) = q j

Next tactic:
have _ : castSucc (castLT j h) = j := castSucc_castLT _ _
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  by_cases h : j.val < n
  · simp only [init, snoc, h, cast_eq, dite_true]
    have _ : castSucc (castLT j h) = j := castSucc_castLT _ _
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ↑j < n
x✝ : castSucc (castLT j h) = j
⊢ q (castSucc (castLT j (_ : ↑j < n))) = q j

Next tactic:
rw [← cast_eq rfl (q j)]
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  by_cases h : j.val < n
  · simp only [init, snoc, h, cast_eq, dite_true]
    have _ : castSucc (castLT j h) = j := castSucc_castLT _ _
    rw [← cast_eq rfl (q j)]
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ↑j < n
x✝ : castSucc (castLT j h) = j
⊢ q (castSucc (castLT j (_ : ↑j < n))) = _root_.cast (_ : α j = α j) (q j)

Next tactic:
congr
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  by_cases h : j.val < n
  · simp only [init, snoc, h, cast_eq, dite_true]
    have _ : castSucc (castLT j h) = j := castSucc_castLT _ _
    rw [← cast_eq rfl (q j)]
    congr
  · 

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ¬↑j < n
⊢ snoc (init q) (q (last n)) j = q j

Next tactic:
rw [eq_last_of_not_lt h]
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q := by
  ext j
  by_cases h : j.val < n
  · simp only [init, snoc, h, cast_eq, dite_true]
    have _ : castSucc (castLT j h) = j := castSucc_castLT _ _
    rw [← cast_eq rfl (q j)]
    congr
  · rw [eq_last_of_not_lt h]
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin (n + 1)
h : ¬↑j < n
⊢ snoc (init q) (q (last n)) (last n) = q (last n)

Next tactic:
simp
/-- Updating the last element of a tuple does not change the beginning. -/
@[simp]
theorem init_update_last : init (update q (last n) z) = init q := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
⊢ init (update q (last n) z) = init q

Next tactic:
ext j
/-- Updating the last element of a tuple does not change the beginning. -/
@[simp]
theorem init_update_last : init (update q (last n) z) = init q := by
  ext j
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin n
⊢ init (update q (last n) z) j = init q j

Next tactic:
simp [init, ne_of_lt, castSucc_lt_last]
/-- Updating an element and taking the beginning commute. -/
@[simp]
theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q) i y := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
⊢ init (update q (castSucc i) y) = update (init q) i y

Next tactic:
ext j
/-- Updating an element and taking the beginning commute. -/
@[simp]
theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q) i y := by
  ext j
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin n
⊢ init (update q (castSucc i) y) j = update (init q) i y j

Next tactic:
by_cases h : j = i
/-- Updating an element and taking the beginning commute. -/
@[simp]
theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q) i y := by
  ext j
  by_cases h : j = i
  · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin n
h : j = i
⊢ init (update q (castSucc i) y) j = update (init q) i y j

Next tactic:
rw [h]
/-- Updating an element and taking the beginning commute. -/
@[simp]
theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q) i y := by
  ext j
  by_cases h : j = i
  · rw [h]
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin n
h : j = i
⊢ init (update q (castSucc i) y) i = update (init q) i y i

Next tactic:
simp [init]
/-- Updating an element and taking the beginning commute. -/
@[simp]
theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q) i y := by
  ext j
  by_cases h : j = i
  · rw [h]
    simp [init]
  · 

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
j : Fin n
h : ¬j = i
⊢ init (update q (castSucc i) y) j = update (init q) i y j

Next tactic:
simp [init, h, castSucc_inj]
/-- `tail` and `init` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem tail_init_eq_init_tail {β : Type*} (q : Fin (n + 2) → β) :
    tail (init q) = init (tail q) := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
β : Type u_1
q : Fin (n + 2) → β
⊢ tail (init q) = init (tail q)

Next tactic:
ext i
/-- `tail` and `init` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem tail_init_eq_init_tail {β : Type*} (q : Fin (n + 2) → β) :
    tail (init q) = init (tail q) := by
  ext i
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
q : Fin (n + 2) → β
i : Fin n
⊢ tail (init q) i = init (tail q) i

Next tactic:
simp [tail, init, castSucc_fin_succ]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i : Fin n
y : α (castSucc i)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
⊢ cons a (snoc q b) = snoc (cons a q) b

Next tactic:
ext i
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
⊢ cons a (snoc q b) i = snoc (cons a q) b i

Next tactic:
by_cases h : i = 0
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : i = 0
⊢ cons a (snoc q b) i = snoc (cons a q) b i

Next tactic:
rw [h]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : i = 0
⊢ cons a (snoc q b) 0 = snoc (cons a q) b 0

Next tactic:
simp [snoc, castLT]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
⊢ cons a (snoc q b) i = snoc (cons a q) b i

Next tactic:
set j := pred i h with ji
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
⊢ cons a (snoc q b) i = snoc (cons a q) b i

Next tactic:
have : i = j.succ := by rw [ji, succ_pred]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  have : i = j.succ := by 

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
⊢ i = succ j

Next tactic:
rw [ji, succ_pred]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  have : i = j.succ := by rw [ji, succ_pred]
  

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
this : i = succ j
⊢ cons a (snoc q b) i = snoc (cons a q) b i

Next tactic:
rw [this, cons_succ]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  have : i = j.succ := by rw [ji, succ_pred]
  rw [this, cons_succ]
  

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
this : i = succ j
⊢ snoc q b j = snoc (cons a q) b (succ j)

Next tactic:
by_cases h' : j.val < n
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  have : i = j.succ := by rw [ji, succ_pred]
  rw [this, cons_succ]
  by_cases h' : j.val < n
  · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
this : i = succ j
h' : ↑j < n
⊢ snoc q b j = snoc (cons a q) b (succ j)

Next tactic:
set k := castLT j h' with jk
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  have : i = j.succ := by rw [ji, succ_pred]
  rw [this, cons_succ]
  by_cases h' : j.val < n
  · set k := castLT j h' with jk
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
this : i = succ j
h' : ↑j < n
k : Fin n := castLT j h'
jk : k = castLT j h'
⊢ snoc q b j = snoc (cons a q) b (succ j)

Next tactic:
have : j = castSucc k := by rw [jk, castSucc_castLT]
/-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b := by
  ext i
  by_cases h : i = 0
  · rw [h]
    -- Porting note: `refl` finished it here in Lean 3, but I had to add more.
    simp [snoc, castLT]
  set j := pred i h with ji
  have : i = j.succ := by rw [ji, succ_pred]
  rw [this, cons_succ]
  by_cases h' : j.val < n
  · set k := castLT j h' with jk
    have : j = castSucc k := by 

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α (last n)
q✝ : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (castSucc i)
i✝ : Fin n
y : α (castSucc i✝)
z : α (last n)
β : Type u_1
a : β
q : Fin n → β
b : β
i : Fin (Nat.succ n + 1)
h : ¬i = 0
j : Fin (n + 1) := pred i h
ji : j = pred i h
this : i = succ j
h' : ↑j < n
k : Fin n := castLT j h'
jk : k = castLT j h'
⊢ j = castSucc k

Next tactic:
rw [jk, castSucc_castLT]