l3lab/ntp-mathlib huggingface dataset:
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  

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

Next tactic:
by_cases h : j = 0
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · 

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

Next tactic:
rw [h]
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    

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

Next tactic:
simp [Ne.symm (succ_ne_zero i)]
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · 

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

Next tactic:
let j' := pred j h
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
⊢ cons x (update p i y) j = update (cons x p) (succ i) y j

Next tactic:
have : j'.succ = j := succ_pred j h
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
⊢ cons x (update p i y) j = update (cons x p) (succ i) y j

Next tactic:
rw [← this, cons_succ]
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this, cons_succ]
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
⊢ update p i y j' = update (cons x p) (succ i) y (succ j')

Next tactic:
by_cases h' : j' = i
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this, cons_succ]
    by_cases h' : j' = i
    · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
h' : j' = i
⊢ update p i y j' = update (cons x p) (succ i) y (succ j')

Next tactic:
rw [h']
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this, cons_succ]
    by_cases h' : j' = i
    · rw [h']
      

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
h' : j' = i
⊢ update p i y i = update (cons x p) (succ i) y (succ i)

Next tactic:
simp
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this, cons_succ]
    by_cases h' : j' = i
    · rw [h']
      simp
    · 

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
h' : ¬j' = i
⊢ update p i y j' = update (cons x p) (succ i) y (succ j')

Next tactic:
have : j'.succ ≠ i.succ := by rwa [Ne.def, succ_inj]
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this, cons_succ]
    by_cases h' : j' = i
    · rw [h']
      simp
    · have : j'.succ ≠ i.succ := by 

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
h' : ¬j' = i
⊢ succ j' ≠ succ i

Next tactic:
rwa [Ne.def, succ_inj]
/-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp [Ne.symm (succ_ne_zero i)]
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this, cons_succ]
    by_cases h' : j' = i
    · rw [h']
      simp
    · have : j'.succ ≠ i.succ := by rwa [Ne.def, succ_inj]
      

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this✝ : succ j' = j
h' : ¬j' = i
this : succ j' ≠ succ i
⊢ update p i y j' = update (cons x p) (succ i) y (succ j')

Next tactic:
rw [update_noteq h', update_noteq this, cons_succ]
/-- As a binary function, `Fin.cons` is injective. -/
theorem cons_injective2 : Function.Injective2 (@cons n α) := fun x₀ y₀ x y h ↦
  ⟨congr_fun h 0, funext fun i ↦ by 

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x✝ : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i✝ : Fin n
y✝ : α (succ i✝)
z x₀ y₀ : α 0
x y : (i : Fin n) → α (succ i)
h : cons x₀ x = cons y₀ y
i : Fin n
⊢ x i = y i

Next tactic:
simpa using congr_fun h (Fin.succ i)
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p := by
  

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

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

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

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

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

Next tactic:
rw [h]
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p := by
  ext j
  by_cases h : j = 0
  · rw [h]
    

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

Next tactic:
simp
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · 

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

Next tactic:
simp only [h, update_noteq, Ne.def, not_false_iff]
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · simp only [h, update_noteq, Ne.def, not_false_iff]
    

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

Next tactic:
let j' := pred j h
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · simp only [h, update_noteq, Ne.def, not_false_iff]
    let j' := pred j h
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
⊢ cons x p j = cons z p j

Next tactic:
have : j'.succ = j := succ_pred j h
/-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · simp only [h, update_noteq, Ne.def, not_false_iff]
    let j' := pred j h
    have : j'.succ = j := succ_pred j h
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
⊢ cons x p j = cons z p j

Next tactic:
rw [← this, cons_succ, cons_succ]
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
⊢ cons (q 0) (tail q) = q

Next tactic:
ext j
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  

Proof state:
case h
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
⊢ cons (q 0) (tail q) j = q j

Next tactic:
by_cases h : j = 0
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · 

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : j = 0
⊢ cons (q 0) (tail q) j = q j

Next tactic:
rw [h]
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · rw [h]
    

Proof state:
case pos
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : j = 0
⊢ cons (q 0) (tail q) 0 = q 0

Next tactic:
simp
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · 

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
⊢ cons (q 0) (tail q) j = q j

Next tactic:
let j' := pred j h
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · let j' := pred j h
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
⊢ cons (q 0) (tail q) j = q j

Next tactic:
have : j'.succ = j := succ_pred j h
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
⊢ cons (q 0) (tail q) j = q j

Next tactic:
rw [← this]
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this]
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
⊢ cons (q 0) (tail q) (succ j') = q (succ j')

Next tactic:
unfold tail
/-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q := by
  ext j
  by_cases h : j = 0
  · rw [h]
    simp
  · let j' := pred j h
    have : j'.succ = j := succ_pred j h
    rw [← this]
    unfold tail
    

Proof state:
case neg
m n : ℕ
α : Fin (n + 1) → Type u
x : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
j : Fin (n + 1)
h : ¬j = 0
j' : Fin n := pred j h
this : succ j' = j
⊢ cons (q 0) (fun i => q (succ i)) (succ j') = q (succ j')

Next tactic:
rw [cons_succ]
/-- Recurse on an `n+1`-tuple by splitting it into a single element and an `n`-tuple. -/
@[elab_as_elim]
def consCases {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀ x, P (Fin.cons x₀ x))
    (x : ∀ i : Fin n.succ, α i) : P x :=
  _root_.cast (by 

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x✝ : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
P : ((i : Fin (Nat.succ n)) → α i) → Sort v
h : (x₀ : α 0) → (x : (i : Fin n) → α (succ i)) → P (cons x₀ x)
x : (i : Fin (Nat.succ n)) → α i
⊢ P (cons (x 0) (tail x)) = P x

Next tactic:
rw [cons_self_tail]
@[simp]
theorem consCases_cons {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀ x, P (Fin.cons x₀ x))
    (x₀ : α 0) (x : ∀ i : Fin n, α i.succ) : @consCases _ _ _ h (cons x₀ x) = h x₀ x := by
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x✝ : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
P : ((i : Fin (Nat.succ n)) → α i) → Sort v
h : (x₀ : α 0) → (x : (i : Fin n) → α (succ i)) → P (cons x₀ x)
x₀ : α 0
x : (i : Fin n) → α (succ i)
⊢ consCases h (cons x₀ x) = h x₀ x

Next tactic:
rw [consCases, cast_eq]
@[simp]
theorem consCases_cons {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀ x, P (Fin.cons x₀ x))
    (x₀ : α 0) (x : ∀ i : Fin n, α i.succ) : @consCases _ _ _ h (cons x₀ x) = h x₀ x := by
  rw [consCases, cast_eq]
  

Proof state:
m n : ℕ
α : Fin (n + 1) → Type u
x✝ : α 0
q : (i : Fin (n + 1)) → α i
p : (i : Fin n) → α (succ i)
i : Fin n
y : α (succ i)
z : α 0
P : ((i : Fin (Nat.succ n)) → α i) → Sort v
h : (x₀ : α 0) → (x : (i : Fin n) → α (succ i)) → P (cons x₀ x)
x₀ : α 0
x : (i : Fin n) → α (succ i)
⊢ h (cons x₀ x 0) (tail (cons x₀ x)) = h x₀ x

Next tactic:
congr
/-- Recurse on a tuple by splitting into `Fin.elim0` and `Fin.cons`. -/
@[elab_as_elim]
def consInduction {α : Type*} {P : ∀ {n : ℕ}, (Fin n → α) → Sort v} (h0 : P Fin.elim0)
    (h : ∀ {n} (x₀) (x : Fin n → α), P x → P (Fin.cons x₀ x)) : ∀ {n : ℕ} (x : Fin n → α), P x
  | 0, x => by 

Proof state:
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
P : {n : ℕ} → (Fin n → α) → Sort v
h0 : P elim0
h : {n : ℕ} → (x₀ : α) → (x : Fin n → α) → P x → P (cons x₀ x)
x : Fin 0 → α
⊢ P x

Next tactic:
convert h0
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  

Proof state:
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
⊢ Injective (cons x₀ x)

Next tactic:
refine' Fin.cases _ _
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · 

Proof state:
case refine'_1
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
⊢ ∀ ⦃a₂ : Fin (n + 1)⦄, cons x₀ x 0 = cons x₀ x a₂ → 0 = a₂

Next tactic:
refine' Fin.cases _ _
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · 

Proof state:
case refine'_1.refine'_1
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
⊢ cons x₀ x 0 = cons x₀ x 0 → 0 = 0

Next tactic:
intro
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · intro
      

Proof state:
case refine'_1.refine'_1
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
a✝ : cons x₀ x 0 = cons x₀ x 0
⊢ 0 = 0

Next tactic:
rfl
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · intro
      rfl
    · 

Proof state:
case refine'_1.refine'_2
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
⊢ ∀ (i : Fin n), cons x₀ x 0 = cons x₀ x (succ i) → 0 = succ i

Next tactic:
intro j h
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · intro
      rfl
    · intro j h
      

Proof state:
case refine'_1.refine'_2
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
j : Fin n
h : cons x₀ x 0 = cons x₀ x (succ j)
⊢ 0 = succ j

Next tactic:
rw [cons_zero, cons_succ] at h
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · intro
      rfl
    · intro j h
      rw [cons_zero, cons_succ] at h
      

Proof state:
case refine'_1.refine'_2
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
j : Fin n
h : x₀ = x j
⊢ 0 = succ j

Next tactic:
exact hx₀.elim ⟨_, h.symm⟩
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · intro
      rfl
    · intro j h
      rw [cons_zero, cons_succ] at h
      exact hx₀.elim ⟨_, h.symm⟩
  · 

Proof state:
case refine'_2
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i : Fin n
y : α✝ (succ i)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
⊢ ∀ (i : Fin n) ⦃a₂ : Fin (n + 1)⦄, cons x₀ x (succ i) = cons x₀ x a₂ → succ i = a₂

Next tactic:
intro i
theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) := by
  refine' Fin.cases _ _
  · refine' Fin.cases _ _
    · intro
      rfl
    · intro j h
      rw [cons_zero, cons_succ] at h
      exact hx₀.elim ⟨_, h.symm⟩
  · intro i
    

Proof state:
case refine'_2
m n : ℕ
α✝ : Fin (n + 1) → Type u
x✝ : α✝ 0
q : (i : Fin (n + 1)) → α✝ i
p : (i : Fin n) → α✝ (succ i)
i✝ : Fin n
y : α✝ (succ i✝)
z : α✝ 0
α : Type u_1
x₀ : α
x : Fin n → α
hx₀ : x₀ ∉ Set.range x
hx : Injective x
i : Fin n
⊢ ∀ ⦃a₂ : Fin (n + 1)⦄, cons x₀ x (succ i) = cons x₀ x a₂ → succ i = a₂

Next tactic:
refine' Fin.cases _ _