File: .lake/packages/lean4/src/lean/Init/Data/Fin/Lemmas.lean

full_name: Fin.size_pos
code: /-- If you actually have an element of `Fin n`, then the `n` is always positive -/
theorem size_pos (i : Fin n) : 0 < n 
goal: 0 < n

full_name: Fin.mod_def
code: theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) 
goal: a % m = ⟨↑a % ↑m, ⋯⟩

full_name: Fin.mul_def
code: theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) 
goal: a * b = ⟨↑a * ↑b % n, ⋯⟩

full_name: Fin.sub_def
code: theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.size_pos) 
goal: a - b = ⟨(n - ↑b + ↑a) % n, ⋯⟩

full_name: Fin.size_pos'
code: theorem size_pos' : ∀ [Nonempty (Fin n)], 0 < n 
goal: 0 < n

full_name: Fin.is_lt
code: @[simp] theorem is_lt (a : Fin n) : (a : Nat) < n 
goal: ↑a < n

full_name: Fin.pos_iff_nonempty
code: theorem pos_iff_nonempty {n : Nat} : 0 < n ↔ Nonempty (Fin n) 
goal: 0 < n ↔ Nonempty (Fin n)

full_name: Fin.eta
code: @[simp] protected theorem eta (a : Fin n) (h : a < n) : (⟨a, h⟩ : Fin n) = a 
goal: ⟨↑a, h⟩ = a

full_name: Fin.ext
code: @[ext] theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b 
goal: a = b

full_name: Fin.ext_iff
code: theorem ext_iff {a b : Fin n} : a = b ↔ a.1 = b.1 
goal: a = b ↔ ↑a = ↑b

full_name: Fin.val_ne_iff
code: theorem val_ne_iff {a b : Fin n} : a.1 ≠ b.1 ↔ a ≠ b 
goal: ↑a ≠ ↑b ↔ a ≠ b

full_name: Fin.forall_iff
code: theorem forall_iff {p : Fin n → Prop} : (∀ i, p i) ↔ ∀ i h, p ⟨i, h⟩ 
goal: (∀ (i : Fin n), p i) ↔ ∀ (i : Nat) (h : i < n), p ⟨i, h⟩

full_name: Fin.mk.inj_iff
code: protected theorem mk.inj_iff {n a b : Nat} {ha : a < n} {hb : b < n} :
    (⟨a, ha⟩ : Fin n) = ⟨b, hb⟩ ↔ a = b 
goal: ⟨a, ha⟩ = ⟨b, hb⟩ ↔ a = b

full_name: Fin.val_mk
code: theorem val_mk {m n : Nat} (h : m < n) : (⟨m, h⟩ : Fin n).val = m 
goal: ↑⟨m, h⟩ = m

full_name: Fin.eq_mk_iff_val_eq
code: theorem eq_mk_iff_val_eq {a : Fin n} {k : Nat} {hk : k < n} :
    a = ⟨k, hk⟩ ↔ (a : Nat) = k 
goal: a = ⟨k, hk⟩ ↔ ↑a = k

full_name: Fin.mk_val
code: theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i 
goal: ⟨↑i, ⋯⟩ = i

full_name: Fin.val_ofNat'
code: @[simp] theorem val_ofNat' (a : Nat) (is_pos : n > 0) :
  (Fin.ofNat' a is_pos).val = a % n 
goal: ↑(Fin.ofNat' a is_pos) = a % n

full_name: Fin.ofNat'_zero_val
code: @[deprecated ofNat'_zero_val (since := "2024-02-22")]
theorem ofNat'_zero_val : (Fin.ofNat' 0 h).val = 0 
goal: ∀ {a : Nat} {h : a > 0}, ↑(Fin.ofNat' 0 h) = 0

full_name: Fin.mod_val
code: @[simp] theorem mod_val (a b : Fin n) : (a % b).val = a.val % b.val 
goal: ↑(a % b) = ↑a % ↑b

full_name: Fin.div_val
code: @[simp] theorem div_val (a b : Fin n) : (a / b).val = a.val / b.val 
goal: ↑(a / b) = ↑a / ↑b

full_name: Fin.modn_val
code: @[simp] theorem modn_val (a : Fin n) (b : Nat) : (a.modn b).val = a.val % b 
goal: ↑(a.modn b) = ↑a % b

full_name: Fin.ite_val
code: theorem ite_val {n : Nat} {c : Prop} [Decidable c] {x : c → Fin n} (y : ¬c → Fin n) :
    (if h : c then x h else y h).val = if h : c then (x h).val else (y h).val 
goal: ↑(if h : c then x h else y h) = if h : c then ↑(x h) else ↑(y h)

full_name: Fin.dite_val
code: theorem dite_val {n : Nat} {c : Prop} [Decidable c] {x y : Fin n} :
    (if c then x else y).val = if c then x.val else y.val 
goal: ↑(if c then x else y) = if c then ↑x else ↑y

full_name: Fin.le_def
code: theorem le_def {a b : Fin n} : a ≤ b ↔ a.1 ≤ b.1 
goal: a ≤ b ↔ ↑a ≤ ↑b

full_name: Fin.lt_def
code: theorem lt_def {a b : Fin n} : a < b ↔ a.1 < b.1 
goal: a < b ↔ ↑a < ↑b

full_name: Fin.lt_iff_val_lt_val
code: theorem lt_iff_val_lt_val {a b : Fin n} : a < b ↔ a.val < b.val 
goal: a < b ↔ ↑a < ↑b

full_name: Fin.not_le
code: @[simp] protected theorem not_le {a b : Fin n} : ¬ a ≤ b ↔ b < a 
goal: ¬a ≤ b ↔ b < a

full_name: Fin.not_lt
code: @[simp] protected theorem not_lt {a b : Fin n} : ¬ a < b ↔ b ≤ a 
goal: ¬a < b ↔ b ≤ a

full_name: Fin.le_refl
code: @[simp] protected theorem le_refl (a : Fin n) : a ≤ a 
goal: a ≤ a

full_name: Fin.lt_irrefl
code: @[simp] protected theorem lt_irrefl (a : Fin n) : ¬ a < a 
goal: ¬a < a

full_name: Fin.le_trans
code: protected theorem le_trans {a b c : Fin n} : a ≤ b → b ≤ c → a ≤ c 
goal: a ≤ b → b ≤ c → a ≤ c

full_name: Fin.lt_trans
code: protected theorem lt_trans {a b c : Fin n} : a < b → b < c → a < c 
goal: a < b → b < c → a < c

full_name: Fin.le_total
code: protected theorem le_total (a b : Fin n) : a ≤ b ∨ b ≤ a 
goal: a ≤ b ∨ b ≤ a

full_name: Fin.lt_asymm
code: protected theorem lt_asymm {a b : Fin n} (h : a < b) : ¬ b < a 
goal: ¬b < a

full_name: Fin.ne_of_lt
code: protected theorem ne_of_lt {a b : Fin n} (h : a < b) : a ≠ b 
goal: a ≠ b

full_name: Fin.ne_of_gt
code: protected theorem ne_of_gt {a b : Fin n} (h : a < b) : b ≠ a 
goal: b ≠ a

full_name: Fin.le_of_lt
code: protected theorem le_of_lt {a b : Fin n} (h : a < b) : a ≤ b 
goal: a ≤ b

full_name: Fin.is_le
code: theorem is_le (i : Fin (n + 1)) : i ≤ n 
goal: ↑i ≤ n

full_name: Fin.is_le'
code: @[simp] theorem is_le' {a : Fin n} : a ≤ n 
goal: ↑a ≤ n

full_name: Fin.mk_lt_of_lt_val
code: theorem mk_lt_of_lt_val {b : Fin n} {a : Nat} (h : a < b) :
    (⟨a, Nat.lt_trans h b.is_lt⟩ : Fin n) < b 
goal: ⟨a, ⋯⟩ < b

full_name: Fin.mk_le_of_le_val
code: theorem mk_le_of_le_val {b : Fin n} {a : Nat} (h : a ≤ b) :
    (⟨a, Nat.lt_of_le_of_lt h b.is_lt⟩ : Fin n) ≤ b 
goal: ⟨a, ⋯⟩ ≤ b

full_name: Fin.mk_le_mk
code: @[simp] theorem mk_le_mk {x y : Nat} {hx hy} : (⟨x, hx⟩ : Fin n) ≤ ⟨y, hy⟩ ↔ x ≤ y 
goal: ⟨x, hx⟩ ≤ ⟨y, hy⟩ ↔ x ≤ y

full_name: Fin.mk_lt_mk
code: @[simp] theorem mk_lt_mk {x y : Nat} {hx hy} : (⟨x, hx⟩ : Fin n) < ⟨y, hy⟩ ↔ x < y 
goal: ⟨x, hx⟩ < ⟨y, hy⟩ ↔ x < y

full_name: Fin.val_zero
code: @[simp] theorem val_zero (n : Nat) : (0 : Fin (n + 1)).1 = 0 
goal: ↑0 = 0

full_name: Fin.mk_zero
code: @[simp] theorem mk_zero : (⟨0, Nat.succ_pos n⟩ : Fin (n + 1)) = 0 
goal: ⟨0, ⋯⟩ = 0

full_name: Fin.zero_le
code: @[simp] theorem zero_le (a : Fin (n + 1)) : 0 ≤ a 
goal: 0 ≤ a

full_name: Fin.zero_lt_one
code: theorem zero_lt_one : (0 : Fin (n + 2)) < 1 
goal: 0 < 1

full_name: Fin.not_lt_zero
code: @[simp] theorem not_lt_zero (a : Fin (n + 1)) : ¬a < 0 
goal: ¬a < 0

full_name: Fin.pos_iff_ne_zero
code: theorem pos_iff_ne_zero {a : Fin (n + 1)} : 0 < a ↔ a ≠ 0 
goal: 0 < a ↔ a ≠ 0

full_name: Fin.eq_zero_or_eq_succ
code: theorem eq_zero_or_eq_succ {n : Nat} : ∀ i : Fin (n + 1), i = 0 ∨ ∃ j : Fin n, i = j.succ
  
goal: i = 0 ∨ ∃ j, i = j.succ

full_name: Fin.eq_succ_of_ne_zero
code: theorem eq_succ_of_ne_zero {n : Nat} {i : Fin (n + 1)} (hi : i ≠ 0) : ∃ j : Fin n, i = j.succ 
goal: ∃ j, i = j.succ

full_name: Fin.val_rev
code: @[simp] theorem val_rev (i : Fin n) : rev i = n - (i + 1) 
goal: ↑i.rev = n - (↑i + 1)

full_name: Fin.rev_rev
code: @[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i 
goal: i.rev.rev = i

full_name: Fin.rev_le_rev
code: @[simp] theorem rev_le_rev {i j : Fin n} : rev i ≤ rev j ↔ j ≤ i 
goal: i.rev ≤ j.rev ↔ j ≤ i

full_name: Fin.rev_inj
code: @[simp] theorem rev_inj {i j : Fin n} : rev i = rev j ↔ i = j 
goal: i.rev = j.rev ↔ i = j

full_name: Fin.rev_eq
code: theorem rev_eq {n a : Nat} (i : Fin (n + 1)) (h : n = a + i) :
    rev i = ⟨a, Nat.lt_succ_of_le (h ▸ Nat.le_add_right ..)⟩ 
goal: i.rev = ⟨a, ⋯⟩

full_name: Fin.rev_lt_rev
code: @[simp] theorem rev_lt_rev {i j : Fin n} : rev i < rev j ↔ j < i 
goal: i.rev < j.rev ↔ j < i

full_name: Fin.val_last
code: @[simp] theorem val_last (n : Nat) : last n = n 
goal: ↑(Fin.last n) = n

full_name: Fin.le_last
code: theorem le_last (i : Fin (n + 1)) : i ≤ last n 
goal: i ≤ Fin.last n

full_name: Fin.last_pos
code: theorem last_pos : (0 : Fin (n + 2)) < last (n + 1) 
goal: 0 < Fin.last (n + 1)

full_name: Fin.eq_last_of_not_lt
code: theorem eq_last_of_not_lt {i : Fin (n + 1)} (h : ¬(i : Nat) < n) : i = last n 
goal: i = Fin.last n

full_name: Fin.val_lt_last
code: theorem val_lt_last {i : Fin (n + 1)} : i ≠ last n → (i : Nat) < n 
goal: i ≠ Fin.last n → ↑i < n

full_name: Fin.rev_last
code: @[simp] theorem rev_last (n : Nat) : rev (last n) = 0 
goal: (Fin.last n).rev = 0

full_name: Fin.rev_zero
code: @[simp] theorem rev_zero (n : Nat) : rev 0 = last n 
goal: Fin.rev 0 = Fin.last n

full_name: Fin.val_one
code: @[simp] theorem val_one (n : Nat) : (1 : Fin (n + 2)).val = 1 
goal: ↑1 = 1

full_name: Fin.mk_one
code: @[simp] theorem mk_one : (⟨1, Nat.succ_lt_succ (Nat.succ_pos n)⟩ : Fin (n + 2)) = (1 : Fin _) 
goal: ⟨1, ⋯⟩ = 1

full_name: Fin.subsingleton_iff_le_one
code: theorem subsingleton_iff_le_one : Subsingleton (Fin n) ↔ n ≤ 1 
goal: Subsingleton (Fin n) ↔ n ≤ 1

full_name: Fin.subsingleton_zero
code: instance subsingleton_zero : Subsingleton (Fin 0) 
goal: Subsingleton (Fin 0)

full_name: Fin.subsingleton_one
code: instance subsingleton_one : Subsingleton (Fin 1) 
goal: Subsingleton (Fin 1)

full_name: Fin.fin_one_eq_zero
code: theorem fin_one_eq_zero (a : Fin 1) : a = 0 
goal: a = 0

full_name: Fin.add_def
code: theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.size_pos) 
goal: a + b = ⟨(↑a + ↑b) % n, ⋯⟩

full_name: Fin.val_add
code: theorem val_add (a b : Fin n) : (a + b).val = (a.val + b.val) % n 
goal: ↑(a + b) = (↑a + ↑b) % n

full_name: Fin.val_add_one_of_lt
code: theorem val_add_one_of_lt {n : Nat} {i : Fin n.succ} (h : i < last _) : (i + 1).1 = i + 1 
goal: ↑(i + 1) = ↑i + 1

full_name: Fin.last_add_one
code: @[simp] theorem last_add_one : ∀ n, last n + 1 = 0
  
goal: Fin.last n + 1 = 0

full_name: Fin.val_add_one
code: theorem val_add_one {n : Nat} (i : Fin (n + 1)) :
    ((i + 1 : Fin (n + 1)) : Nat) = if i = last _ then (0 : Nat) else i + 1 
goal: ↑(i + 1) = if i = Fin.last n then 0 else ↑i + 1

full_name: Fin.val_two
code: @[simp] theorem val_two {n : Nat} : (2 : Fin (n + 3)).val = 2 
goal: ↑2 = 2

full_name: Fin.add_one_pos
code: theorem add_one_pos (i : Fin (n + 1)) (h : i < Fin.last n) : (0 : Fin (n + 1)) < i + 1 
goal: 0 < i + 1

full_name: Fin.one_pos
code: theorem one_pos : (0 : Fin (n + 2)) < 1 
goal: 0 < 1

full_name: Fin.zero_ne_one
code: theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 
goal: 0 ≠ 1

full_name: Fin.val_succ
code: @[simp] theorem val_succ (j : Fin n) : (j.succ : Nat) = j + 1 
goal: ↑j.succ = ↑j + 1

full_name: Fin.succ_pos
code: @[simp] theorem succ_pos (a : Fin n) : (0 : Fin (n + 1)) < a.succ 
goal: 0 < a.succ

full_name: Fin.succ_le_succ_iff
code: @[simp] theorem succ_le_succ_iff {a b : Fin n} : a.succ ≤ b.succ ↔ a ≤ b 
goal: a.succ ≤ b.succ ↔ a ≤ b

full_name: Fin.succ_lt_succ_iff
code: @[simp] theorem succ_lt_succ_iff {a b : Fin n} : a.succ < b.succ ↔ a < b 
goal: a.succ < b.succ ↔ a < b

full_name: Fin.succ_inj
code: @[simp] theorem succ_inj {a b : Fin n} : a.succ = b.succ ↔ a = b 
goal: a.succ = b.succ ↔ a = b

full_name: Fin.succ_ne_zero
code: theorem succ_ne_zero {n} : ∀ k : Fin n, Fin.succ k ≠ 0
  
goal: k.succ ≠ 0

full_name: Fin.succ_zero_eq_one
code: @[simp] theorem succ_zero_eq_one : Fin.succ (0 : Fin (n + 1)) = 1 
goal: Fin.succ 0 = 1

full_name: Fin.succ_one_eq_two
code: /-- Version of `succ_one_eq_two` to be used by `dsimp` -/
@[simp] theorem succ_one_eq_two : Fin.succ (1 : Fin (n + 2)) = 2 
goal: Fin.succ 1 = 2

full_name: Fin.succ_mk
code: @[simp] theorem succ_mk (n i : Nat) (h : i < n) :
    Fin.succ ⟨i, h⟩ = ⟨i + 1, Nat.succ_lt_succ h⟩ 
goal: ⟨i, h⟩.succ = ⟨i + 1, ⋯⟩

full_name: Fin.mk_succ_pos
code: theorem mk_succ_pos (i : Nat) (h : i < n) :
    (0 : Fin (n + 1)) < ⟨i.succ, Nat.add_lt_add_right h 1⟩ 
goal: 0 < ⟨i.succ, ⋯⟩

full_name: Fin.one_lt_succ_succ
code: theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ 
goal: 1 < a.succ.succ

full_name: Fin.add_one_lt_iff
code: @[simp] theorem add_one_lt_iff {n : Nat} {k : Fin (n + 2)} : k + 1 < k ↔ k = last _ 
goal: k + 1 < k ↔ k = Fin.last (n + 1)

full_name: Fin.add_one_le_iff
code: @[simp] theorem add_one_le_iff {n : Nat} : ∀ {k : Fin (n + 1)}, k + 1 ≤ k ↔ k = last _ 
goal: k + 1 ≤ k ↔ k = Fin.last n

full_name: Fin.last_le_iff
code: @[simp] theorem last_le_iff {n : Nat} {k : Fin (n + 1)} : last n ≤ k ↔ k = last n 
goal: Fin.last n ≤ k ↔ k = Fin.last n

full_name: Fin.lt_add_one_iff
code: @[simp] theorem lt_add_one_iff {n : Nat} {k : Fin (n + 1)} : k < k + 1 ↔ k < last n 
goal: k < k + 1 ↔ k < Fin.last n

full_name: Fin.le_zero_iff
code: @[simp] theorem le_zero_iff {n : Nat} {k : Fin (n + 1)} : k ≤ 0 ↔ k = 0 
goal: k ≤ 0 ↔ k = 0

full_name: Fin.succ_succ_ne_one
code: theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 
goal: a.succ.succ ≠ 1

full_name: Fin.coe_castLT
code: @[simp] theorem coe_castLT (i : Fin m) (h : i.1 < n) : (castLT i h : Nat) = i 
goal: ↑(i.castLT h) = ↑i

full_name: Fin.castLT_mk
code: @[simp] theorem castLT_mk (i n m : Nat) (hn : i < n) (hm : i < m) : castLT ⟨i, hn⟩ hm = ⟨i, hm⟩ 
goal: ⟨i, hn⟩.castLT hm = ⟨i, hm⟩

full_name: Fin.coe_castLE
code: @[simp] theorem coe_castLE (h : n ≤ m) (i : Fin n) : (castLE h i : Nat) = i 
goal: ↑(Fin.castLE h i) = ↑i

full_name: Fin.castLE_mk
code: @[simp] theorem castLE_mk (i n m : Nat) (hn : i < n) (h : n ≤ m) :
    castLE h ⟨i, hn⟩ = ⟨i, Nat.lt_of_lt_of_le hn h⟩ 
goal: Fin.castLE h ⟨i, hn⟩ = ⟨i, ⋯⟩

full_name: Fin.castLE_zero
code: @[simp] theorem castLE_zero {n m : Nat} (h : n.succ ≤ m.succ) : castLE h 0 = 0 
goal: Fin.castLE h 0 = 0

full_name: Fin.castLE_succ
code: @[simp] theorem castLE_succ {m n : Nat} (h : m + 1 ≤ n + 1) (i : Fin m) :
    castLE h i.succ = (castLE (Nat.succ_le_succ_iff.mp h) i).succ 
goal: Fin.castLE h i.succ = (Fin.castLE ⋯ i).succ

full_name: Fin.castLE_castLE
code: @[simp] theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (i : Fin k) :
    Fin.castLE mn (Fin.castLE km i) = Fin.castLE (Nat.le_trans km mn) i 
goal: Fin.castLE mn (Fin.castLE km i) = Fin.castLE ⋯ i

full_name: Fin.castLE_comp_castLE
code: @[simp] theorem castLE_comp_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) :
    Fin.castLE mn ∘ Fin.castLE km = Fin.castLE (Nat.le_trans km mn) 
goal: Fin.castLE mn ∘ Fin.castLE km = Fin.castLE ⋯

full_name: Fin.coe_cast
code: @[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i 
goal: ↑(Fin.cast h i) = ↑i

full_name: Fin.cast_last
code: @[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' 
goal: Fin.cast h (Fin.last n) = Fin.last n'

full_name: Fin.cast_mk
code: @[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ 
goal: Fin.cast h ⟨i, hn⟩ = ⟨i, ⋯⟩

full_name: Fin.cast_trans
code: @[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
    cast h' (cast h i) = cast (Eq.trans h h') i 
goal: Fin.cast h' (Fin.cast h i) = Fin.cast ⋯ i

full_name: Fin.castLE_of_eq
code: theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h 
goal: Fin.castLE h' = Fin.cast h

full_name: Fin.coe_castAdd
code: @[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i 
goal: ↑(Fin.castAdd m i) = ↑i

full_name: Fin.castAdd_zero
code: @[simp] theorem castAdd_zero : (castAdd 0 : Fin n → Fin (n + 0)) = cast rfl 
goal: Fin.castAdd 0 = Fin.cast ⋯

full_name: Fin.castAdd_lt
code: theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m 
goal: ↑(Fin.castAdd n i) < m

full_name: Fin.castAdd_mk
code: @[simp] theorem castAdd_mk (m : Nat) (i : Nat) (h : i < n) :
    castAdd m ⟨i, h⟩ = ⟨i, Nat.lt_add_right m h⟩ 
goal: Fin.castAdd m ⟨i, h⟩ = ⟨i, ⋯⟩

full_name: Fin.castAdd_castLT
code: @[simp] theorem castAdd_castLT (m : Nat) (i : Fin (n + m)) (hi : i.val < n) :
    castAdd m (castLT i hi) = i 
goal: Fin.castAdd m (i.castLT hi) = i

full_name: Fin.castLT_castAdd
code: @[simp] theorem castLT_castAdd (m : Nat) (i : Fin n) :
    castLT (castAdd m i) (castAdd_lt m i) = i 
goal: (Fin.castAdd m i).castLT ⋯ = i

full_name: Fin.castAdd_cast
code: /-- For rewriting in the reverse direction, see `Fin.cast_castAdd_left`. -/
theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
    castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) 
goal: Fin.castAdd m (Fin.cast h i) = Fin.cast ⋯ (Fin.castAdd m i)

full_name: Fin.cast_castAdd_left
code: theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
    cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) 
goal: Fin.cast h (Fin.castAdd m i) = Fin.castAdd m (Fin.cast ⋯ i)

full_name: Fin.cast_castAdd_right
code: @[simp] theorem cast_castAdd_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
    cast h (castAdd m' i) = castAdd m i 
goal: Fin.cast h (Fin.castAdd m' i) = Fin.castAdd m i

full_name: Fin.castAdd_castAdd
code: theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
    castAdd p (castAdd n i) = cast (Nat.add_assoc ..).symm (castAdd (n + p) i) 
goal: Fin.castAdd p (Fin.castAdd n i) = Fin.cast ⋯ (Fin.castAdd (n + p) i)

full_name: Fin.cast_succ_eq
code: /-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
the reverse direction. -/
@[simp] theorem cast_succ_eq {n' : Nat} (i : Fin n) (h : n.succ = n'.succ) :
    cast h i.succ = (cast (Nat.succ.inj h) i).succ 
goal: Fin.cast h i.succ = (Fin.cast ⋯ i).succ

full_name: Fin.succ_cast_eq
code: theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
    (cast h i).succ = cast (by rw [h]) i.succ 
goal: (Fin.cast h i).succ = Fin.cast ⋯ i.succ

full_name: Fin.coe_castSucc
code: @[simp] theorem coe_castSucc (i : Fin n) : (Fin.castSucc i : Nat) = i 
goal: ↑i.castSucc = ↑i

full_name: Fin.castSucc_mk
code: @[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc ⟨i, h⟩ = ⟨i, Nat.lt.step h⟩ 
goal: ⟨i, h⟩.castSucc = ⟨i, ⋯⟩

full_name: Fin.cast_castSucc
code: @[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
    cast h (castSucc i) = castSucc (cast (Nat.succ.inj h) i) 
goal: Fin.cast h i.castSucc = (Fin.cast ⋯ i).castSucc

full_name: Fin.castSucc_lt_succ
code: theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ 
goal: i.castSucc < i.succ

full_name: Fin.le_castSucc_iff
code: theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ Fin.castSucc j ↔ i < j.succ 
goal: i ≤ j.castSucc ↔ i < j.succ

full_name: Fin.castSucc_lt_iff_succ_le
code: theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
    Fin.castSucc i < j ↔ i.succ ≤ j 
goal: i.castSucc < j ↔ i.succ ≤ j

full_name: Fin.succ_last
code: @[simp] theorem succ_last (n : Nat) : (last n).succ = last n.succ 
goal: (Fin.last n).succ = Fin.last n.succ

full_name: Fin.succ_eq_last_succ
code: @[simp] theorem succ_eq_last_succ {n : Nat} (i : Fin n.succ) :
    i.succ = last (n + 1) ↔ i = last n 
goal: i.succ = Fin.last (n + 1) ↔ i = Fin.last n

full_name: Fin.castSucc_castLT
code: @[simp] theorem castSucc_castLT (i : Fin (n + 1)) (h : (i : Nat) < n) :
    castSucc (castLT i h) = i 
goal: (i.castLT h).castSucc = i

full_name: Fin.castLT_castSucc
code: @[simp] theorem castLT_castSucc {n : Nat} (a : Fin n) (h : (a : Nat) < n) :
    castLT (castSucc a) h = a 
goal: a.castSucc.castLT h = a

full_name: Fin.castSucc_lt_castSucc_iff
code: @[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
    Fin.castSucc a < Fin.castSucc b ↔ a < b 
goal: a.castSucc < b.castSucc ↔ a < b

full_name: Fin.castSucc_inj
code: theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b 
goal: a.castSucc = b.castSucc ↔ a = b

full_name: Fin.castSucc_lt_last
code: theorem castSucc_lt_last (a : Fin n) : castSucc a < last n 
goal: a.castSucc < Fin.last n

full_name: Fin.castSucc_zero
code: @[simp] theorem castSucc_zero : castSucc (0 : Fin (n + 1)) = 0 
goal: Fin.castSucc 0 = 0

full_name: Fin.castSucc_one
code: @[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 
goal: Fin.castSucc 1 = 1

full_name: Fin.castSucc_pos
code: /-- `castSucc i` is positive when `i` is positive -/
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i 
goal: 0 < i.castSucc

full_name: Fin.castSucc_eq_zero_iff
code: @[simp] theorem castSucc_eq_zero_iff (a : Fin (n + 1)) : castSucc a = 0 ↔ a = 0 
goal: a.castSucc = 0 ↔ a = 0

full_name: Fin.castSucc_ne_zero_iff
code: theorem castSucc_ne_zero_iff (a : Fin (n + 1)) : castSucc a ≠ 0 ↔ a ≠ 0 
goal: a.castSucc ≠ 0 ↔ a ≠ 0

full_name: Fin.castSucc_fin_succ
code: theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
    castSucc (Fin.succ j) = Fin.succ (castSucc j) 
goal: j.succ.castSucc = j.castSucc.succ

full_name: Fin.coeSucc_eq_succ
code: @[simp]
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ 
goal: a.castSucc + 1 = a.succ

full_name: Fin.lt_succ
code: theorem lt_succ {a : Fin n} : castSucc a < a.succ 
goal: a.castSucc < a.succ

full_name: Fin.exists_castSucc_eq
code: theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : (∃ j, castSucc j = i) ↔ i ≠ last n 
goal: (∃ j, j.castSucc = i) ↔ i ≠ Fin.last n

full_name: Fin.succ_castSucc
code: theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = castSucc i.succ 
goal: i.castSucc.succ = i.succ.castSucc

full_name: Fin.coe_addNat
code: @[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m 
goal: ↑(i.addNat m) = ↑i + m

full_name: Fin.addNat_one
code: @[simp] theorem addNat_one {i : Fin n} : addNat i 1 = i.succ 
goal: i.addNat 1 = i.succ

full_name: Fin.le_coe_addNat
code: theorem le_coe_addNat (m : Nat) (i : Fin n) : m ≤ addNat i m 
goal: m ≤ ↑(i.addNat m)

full_name: Fin.addNat_mk
code: @[simp] theorem addNat_mk (n i : Nat) (hi : i < m) :
    addNat ⟨i, hi⟩ n = ⟨i + n, Nat.add_lt_add_right hi n⟩ 
goal: ⟨i, hi⟩.addNat n = ⟨i + n, ⋯⟩

full_name: Fin.cast_addNat_zero
code: @[simp] theorem cast_addNat_zero {n n' : Nat} (i : Fin n) (h : n + 0 = n') :
    cast h (addNat i 0) = cast ((Nat.add_zero _).symm.trans h) i 
goal: Fin.cast h (i.addNat 0) = Fin.cast ⋯ i

full_name: Fin.addNat_cast
code: /-- For rewriting in the reverse direction, see `Fin.cast_addNat_left`. -/
theorem addNat_cast {n n' m : Nat} (i : Fin n') (h : n' = n) :
    addNat (cast h i) m = cast (congrArg (. + m) h) (addNat i m) 
goal: (Fin.cast h i).addNat m = Fin.cast ⋯ (i.addNat m)

full_name: Fin.cast_addNat_left
code: theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
    cast h (addNat i m) = addNat (cast (Nat.add_right_cancel h) i) m 
goal: Fin.cast h (i.addNat m) = (Fin.cast ⋯ i).addNat m

full_name: Fin.cast_addNat_right
code: @[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
    cast h (addNat i m') = addNat i m 
goal: Fin.cast h (i.addNat m') = i.addNat m

full_name: Fin.coe_natAdd
code: @[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i 
goal: ↑(Fin.natAdd n i) = n + ↑i

full_name: Fin.natAdd_mk
code: @[simp] theorem natAdd_mk (n i : Nat) (hi : i < m) :
    natAdd n ⟨i, hi⟩ = ⟨n + i, Nat.add_lt_add_left hi n⟩ 
goal: Fin.natAdd n ⟨i, hi⟩ = ⟨n + i, ⋯⟩

full_name: Fin.le_coe_natAdd
code: theorem le_coe_natAdd (m : Nat) (i : Fin n) : m ≤ natAdd m i 
goal: m ≤ ↑(Fin.natAdd m i)

full_name: Fin.natAdd_zero
code: theorem natAdd_zero {n : Nat} : natAdd 0 = cast (Nat.zero_add n).symm 
goal: Fin.natAdd 0 = Fin.cast ⋯

full_name: Fin.natAdd_cast
code: /-- For rewriting in the reverse direction, see `Fin.cast_natAdd_right`. -/
theorem natAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
    natAdd m (cast h i) = cast (congrArg _ h) (natAdd m i) 
goal: Fin.natAdd m (Fin.cast h i) = Fin.cast ⋯ (Fin.natAdd m i)

full_name: Fin.cast_natAdd_right
code: theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
    cast h (natAdd m i) = natAdd m (cast (Nat.add_left_cancel h) i) 
goal: Fin.cast h (Fin.natAdd m i) = Fin.natAdd m (Fin.cast ⋯ i)

full_name: Fin.cast_natAdd_left
code: @[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
    cast h (natAdd m' i) = natAdd m i 
goal: Fin.cast h (Fin.natAdd m' i) = Fin.natAdd m i

full_name: Fin.castAdd_natAdd
code: theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
    castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) 
goal: Fin.castAdd p (Fin.natAdd m i) = Fin.cast ⋯ (Fin.natAdd m (Fin.castAdd p i))

full_name: Fin.natAdd_castAdd
code: theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
    natAdd m (castAdd p i) = cast (Nat.add_assoc ..) (castAdd p (natAdd m i)) 
goal: Fin.natAdd m (Fin.castAdd p i) = Fin.cast ⋯ (Fin.castAdd p (Fin.natAdd m i))

full_name: Fin.natAdd_natAdd
code: theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
    natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) 
goal: Fin.natAdd m (Fin.natAdd n i) = Fin.cast ⋯ (Fin.natAdd (m + n) i)

full_name: Fin.cast_natAdd_zero
code: @[simp]
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
    cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i 
goal: Fin.cast h (Fin.natAdd 0 i) = Fin.cast ⋯ i

full_name: Fin.cast_natAdd
code: @[simp]
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
    cast (Nat.add_comm ..) (natAdd n i) = addNat i n 
goal: Fin.cast ⋯ (Fin.natAdd n i) = i.addNat n

full_name: Fin.cast_addNat
code: @[simp]
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
    cast (Nat.add_comm ..) (addNat i m) = natAdd m i 
goal: Fin.cast ⋯ (i.addNat m) = Fin.natAdd m i

full_name: Fin.natAdd_last
code: @[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) 
goal: Fin.natAdd n (Fin.last m) = Fin.last (n + m)

full_name: Fin.natAdd_castSucc
code: theorem natAdd_castSucc {m n : Nat} {i : Fin m} : natAdd n (castSucc i) = castSucc (natAdd n i) 
goal: Fin.natAdd n i.castSucc = (Fin.natAdd n i).castSucc

full_name: Fin.rev_castAdd
code: theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m 
goal: (Fin.castAdd m k).rev = k.rev.addNat m

full_name: Fin.rev_addNat
code: theorem rev_addNat (k : Fin n) (m : Nat) : rev (addNat k m) = castAdd m (rev k) 
goal: (k.addNat m).rev = Fin.castAdd m k.rev

full_name: Fin.rev_castSucc
code: theorem rev_castSucc (k : Fin n) : rev (castSucc k) = succ (rev k) 
goal: k.castSucc.rev = k.rev.succ

full_name: Fin.rev_succ
code: theorem rev_succ (k : Fin n) : rev (succ k) = castSucc (rev k) 
goal: k.succ.rev = k.rev.castSucc

full_name: Fin.coe_pred
code: @[simp] theorem coe_pred (j : Fin (n + 1)) (h : j ≠ 0) : (j.pred h : Nat) = j - 1 
goal: ↑(j.pred h) = ↑j - 1

full_name: Fin.succ_pred
code: @[simp] theorem succ_pred : ∀ (i : Fin (n + 1)) (h : i ≠ 0), (i.pred h).succ = i
  
goal: (i.pred h).succ = i

full_name: Fin.pred_succ
code: @[simp]
theorem pred_succ (i : Fin n) {h : i.succ ≠ 0} : i.succ.pred h = i 
goal: i.succ.pred h = i

full_name: Fin.pred_eq_iff_eq_succ
code: theorem pred_eq_iff_eq_succ {n : Nat} (i : Fin (n + 1)) (hi : i ≠ 0) (j : Fin n) :
    i.pred hi = j ↔ i = j.succ 
goal: i.pred hi = j ↔ i = j.succ

full_name: Fin.pred_mk_succ
code: theorem pred_mk_succ (i : Nat) (h : i < n + 1) :
    Fin.pred ⟨i + 1, Nat.add_lt_add_right h 1⟩ (ne_of_val_ne (Nat.ne_of_gt (mk_succ_pos i h))) =
      ⟨i, h⟩ 
goal: ⟨i + 1, ⋯⟩.pred ⋯ = ⟨i, h⟩

full_name: Fin.pred_mk_succ'
code: @[simp] theorem pred_mk_succ' (i : Nat) (h₁ : i + 1 < n + 1 + 1) (h₂) :
    Fin.pred ⟨i + 1, h₁⟩ h₂ = ⟨i, Nat.lt_of_succ_lt_succ h₁⟩ 
goal: ⟨i + 1, h₁⟩.pred h₂ = ⟨i, ⋯⟩

full_name: Fin.pred_mk
code: theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w =
    ⟨i - 1, Nat.sub_lt_right_of_lt_add (Nat.pos_iff_ne_zero.2 (Fin.val_ne_of_ne w)) h⟩ 
goal: ⟨i, h⟩.pred w = ⟨i - 1, ⋯⟩

full_name: Fin.pred_le_pred_iff
code: @[simp] theorem pred_le_pred_iff {n : Nat} {a b : Fin n.succ} {ha : a ≠ 0} {hb : b ≠ 0} :
    a.pred ha ≤ b.pred hb ↔ a ≤ b 
goal: a.pred ha ≤ b.pred hb ↔ a ≤ b

full_name: Fin.pred_lt_pred_iff
code: @[simp] theorem pred_lt_pred_iff {n : Nat} {a b : Fin n.succ} {ha : a ≠ 0} {hb : b ≠ 0} :
    a.pred ha < b.pred hb ↔ a < b 
goal: a.pred ha < b.pred hb ↔ a < b

full_name: Fin.pred_inj
code: @[simp] theorem pred_inj :
    ∀ {a b : Fin (n + 1)} {ha : a ≠ 0} {hb : b ≠ 0}, a.pred ha = b.pred hb ↔ a = b
  
goal: a.pred ha = b.pred hb ↔ a = b

full_name: Fin.pred_one
code: @[simp] theorem pred_one {n : Nat} :
    Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 
goal: Fin.pred 1 ⋯ = 0

full_name: Fin.pred_add_one
code: theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
    pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h 
goal: (i + 1).pred ⋯ = i.castLT h

full_name: Fin.coe_subNat
code: @[simp] theorem coe_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m 
goal: ↑(Fin.subNat m i h) = ↑i - m

full_name: Fin.subNat_mk
code: @[simp] theorem subNat_mk {i : Nat} (h₁ : i < n + m) (h₂ : m ≤ i) :
    subNat m ⟨i, h₁⟩ h₂ = ⟨i - m, Nat.sub_lt_right_of_lt_add h₂ h₁⟩ 
goal: Fin.subNat m ⟨i, h₁⟩ h₂ = ⟨i - m, ⋯⟩

full_name: Fin.pred_castSucc_succ
code: @[simp] theorem pred_castSucc_succ (i : Fin n) :
    pred (castSucc i.succ) (Fin.ne_of_gt (castSucc_pos i.succ_pos)) = castSucc i 
goal: i.succ.castSucc.pred ⋯ = i.castSucc

full_name: Fin.addNat_subNat
code: @[simp] theorem addNat_subNat {i : Fin (n + m)} (h : m ≤ i) : addNat (subNat m i h) m = i 
goal: (Fin.subNat m i h).addNat m = i

full_name: Fin.subNat_addNat
code: @[simp] theorem subNat_addNat (i : Fin n) (m : Nat) (h : m ≤ addNat i m := le_coe_addNat m i) :
    subNat m (addNat i m) h = i 
goal: Fin.subNat m (i.addNat m) h = i

full_name: Fin.natAdd_subNat_cast
code: @[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n ≤ i) :
    natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i 
goal: Fin.natAdd n (Fin.subNat n (Fin.cast ⋯ i) h) = i

full_name: Fin.succRec
code: /-- Define `motive n i` by induction on `i : Fin n` interpreted as `(0 : Fin (n - i)).succ.succ…`.
This function has two arguments: `zero n` defines `0`-th element `motive (n+1) 0` of an
`(n+1)`-tuple, and `succ n i` defines `(i+1)`-st element of `(n+1)`-tuple based on `n`, `i`, and
`i`-th element of `n`-tuple. -/
-- FIXME: Performance review
@[elab_as_elim] def succRec {motive : ∀ n, Fin n → Sort _}
    (zero : ∀ n, motive n.succ (0 : Fin (n + 1)))
    (succ : ∀ n i, motive n i → motive n.succ i.succ) : ∀ {n : Nat} (i : Fin n), motive n i
  
goal: motive n i

full_name: Fin.succRecOn
code: /-- Define `motive n i` by induction on `i : Fin n` interpreted as `(0 : Fin (n - i)).succ.succ…`.
This function has two arguments:
`zero n` defines the `0`-th element `motive (n+1) 0` of an `(n+1)`-tuple, and
`succ n i` defines the `(i+1)`-st element of an `(n+1)`-tuple based on `n`, `i`,
and the `i`-th element of an `n`-tuple.

A version of `Fin.succRec` taking `i : Fin n` as the first argument. -/
-- FIXME: Performance review
@[elab_as_elim] def succRecOn {n : Nat} (i : Fin n) {motive : ∀ n, Fin n → Sort _}
    (zero : ∀ n, motive (n + 1) 0) (succ : ∀ n i, motive n i → motive (Nat.succ n) i.succ) :
    motive n i 
goal: motive n i

full_name: Fin.succRecOn_zero
code: @[simp] theorem succRecOn_zero {motive : ∀ n, Fin n → Sort _} {zero succ} (n) :
    @Fin.succRecOn (n + 1) 0 motive zero succ = zero n 
goal: Fin.succRecOn 0 zero succ = zero n

full_name: Fin.succRecOn_succ
code: @[simp] theorem succRecOn_succ {motive : ∀ n, Fin n → Sort _} {zero succ} {n} (i : Fin n) :
    @Fin.succRecOn (n + 1) i.succ motive zero succ = succ n i (Fin.succRecOn i zero succ) 
goal: i.succ.succRecOn zero succ = succ n i (i.succRecOn zero succ)

full_name: Fin.induction
code: /-- Define `motive i` by induction on `i : Fin (n + 1)` via induction on the underlying `Nat` value.
This function has two arguments: `zero` handles the base case on `motive 0`,
and `succ` defines the inductive step using `motive i.castSucc`.
-/
-- FIXME: Performance review
@[elab_as_elim] def induction {motive : Fin (n + 1) → Sort _} (zero : motive 0)
    (succ : ∀ i : Fin n, motive (castSucc i) → motive i.succ) :
    ∀ i : Fin (n + 1), motive i
  
goal: motive i

full_name: Fin.induction.go
code: /-- Define `motive i` by induction on `i : Fin (n + 1)` via induction on the underlying `Nat` value.
This function has two arguments: `zero` handles the base case on `motive 0`,
and `succ` defines the inductive step using `motive i.castSucc`.
-/
-- FIXME: Performance review
@[elab_as_elim] def induction {motive : Fin (n + 1) → Sort _} (zero : motive 0)
    (succ : ∀ i : Fin n, motive (castSucc i) → motive i.succ) :
    ∀ i : Fin (n + 1), motive i
  
goal: motive ⟨i, hi⟩

full_name: Fin.induction_zero
code: @[simp] theorem induction_zero {motive : Fin (n + 1) → Sort _} (zero : motive 0)
    (hs : ∀ i : Fin n, motive (castSucc i) → motive i.succ) :
    (induction zero hs : ∀ i : Fin (n + 1), motive i) 0 = zero 
goal: (fun i => Fin.induction zero hs i) 0 = zero

full_name: Fin.induction_succ
code: @[simp] theorem induction_succ {motive : Fin (n + 1) → Sort _} (zero : motive 0)
    (succ : ∀ i : Fin n, motive (castSucc i) → motive i.succ) (i : Fin n) :
    induction (motive := motive) zero succ i.succ = succ i (induction zero succ (castSucc i)) 
goal: Fin.induction zero succ i.succ = succ i (Fin.induction zero succ i.castSucc)

full_name: Fin.inductionOn
code: /-- Define `motive i` by induction on `i : Fin (n + 1)` via induction on the underlying `Nat` value.
This function has two arguments: `zero` handles the base case on `motive 0`,
and `succ` defines the inductive step using `motive i.castSucc`.

A version of `Fin.induction` taking `i : Fin (n + 1)` as the first argument.
-/
-- FIXME: Performance review
@[elab_as_elim] def inductionOn (i : Fin (n + 1)) {motive : Fin (n + 1) → Sort _} (zero : motive 0)
    (succ : ∀ i : Fin n, motive (castSucc i) → motive i.succ) : motive i 
goal: motive i

full_name: Fin.cases
code: /-- Define `f : Π i : Fin n.succ, motive i` by separately handling the cases `i = 0` and
`i = j.succ`, `j : Fin n`. -/
@[elab_as_elim] def cases {motive : Fin (n + 1) → Sort _}
    (zero : motive 0) (succ : ∀ i : Fin n, motive i.succ) :
    ∀ i : Fin (n + 1), motive i 
goal: motive i

full_name: Fin.cases_zero
code: @[simp] theorem cases_zero {n} {motive : Fin (n + 1) → Sort _} {zero succ} :
    @Fin.cases n motive zero succ 0 = zero 
goal: Fin.cases zero succ 0 = zero

full_name: Fin.cases_succ
code: @[simp] theorem cases_succ {n} {motive : Fin (n + 1) → Sort _} {zero succ} (i : Fin n) :
    @Fin.cases n motive zero succ i.succ = succ i 
goal: Fin.cases zero succ i.succ = succ i

full_name: Fin.cases_succ'
code: @[simp] theorem cases_succ' {n} {motive : Fin (n + 1) → Sort _} {zero succ}
    {i : Nat} (h : i + 1 < n + 1) :
    @Fin.cases n motive zero succ ⟨i.succ, h⟩ = succ ⟨i, Nat.lt_of_succ_lt_succ h⟩ 
goal: Fin.cases zero succ ⟨i.succ, h⟩ = succ ⟨i, ⋯⟩

full_name: Fin.forall_fin_succ
code: theorem forall_fin_succ {P : Fin (n + 1) → Prop} : (∀ i, P i) ↔ P 0 ∧ ∀ i : Fin n, P i.succ 
goal: (∀ (i : Fin (n + 1)), P i) ↔ P 0 ∧ ∀ (i : Fin n), P i.succ

full_name: Fin.exists_fin_succ
code: theorem exists_fin_succ {P : Fin (n + 1) → Prop} : (∃ i, P i) ↔ P 0 ∨ ∃ i : Fin n, P i.succ 
goal: (∃ i, P i) ↔ P 0 ∨ ∃ i, P i.succ

full_name: Fin.forall_fin_one
code: theorem forall_fin_one {p : Fin 1 → Prop} : (∀ i, p i) ↔ p 0 
goal: (∀ (i : Fin 1), p i) ↔ p 0

full_name: Fin.exists_fin_one
code: theorem exists_fin_one {p : Fin 1 → Prop} : (∃ i, p i) ↔ p 0 
goal: (∃ i, p i) ↔ p 0

full_name: Fin.forall_fin_two
code: theorem forall_fin_two {p : Fin 2 → Prop} : (∀ i, p i) ↔ p 0 ∧ p 1 
goal: (∀ (i : Fin 2), p i) ↔ p 0 ∧ p 1

full_name: Fin.exists_fin_two
code: theorem exists_fin_two {p : Fin 2 → Prop} : (∃ i, p i) ↔ p 0 ∨ p 1 
goal: (∃ i, p i) ↔ p 0 ∨ p 1

full_name: Fin.fin_two_eq_of_eq_zero_iff
code: theorem fin_two_eq_of_eq_zero_iff : ∀ {a b : Fin 2}, (a = 0 ↔ b = 0) → a = b 
goal: (a = 0 ↔ b = 0) → a = b

full_name: Fin.reverseInduction
code: /--
Define `motive i` by reverse induction on `i : Fin (n + 1)` via induction on the underlying `Nat`
value. This function has two arguments: `last` handles the base case on `motive (Fin.last n)`,
and `cast` defines the inductive step using `motive i.succ`, inducting downwards.
-/
@[elab_as_elim] def reverseInduction {motive : Fin (n + 1) → Sort _} (last : motive (Fin.last n))
    (cast : ∀ i : Fin n, motive i.succ → motive (castSucc i)) (i : Fin (n + 1)) : motive i 
goal: motive i

full_name: Fin.reverseInduction_last
code: @[simp] theorem reverseInduction_last {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ} :
    (reverseInduction zero succ (Fin.last n) : motive (Fin.last n)) = zero 
goal: Fin.reverseInduction zero succ (Fin.last n) = zero

full_name: Fin.reverseInduction_castSucc
code: @[simp] theorem reverseInduction_castSucc {n : Nat} {motive : Fin (n + 1) → Sort _} {zero succ}
    (i : Fin n) : reverseInduction (motive := motive) zero succ (castSucc i) =
      succ i (reverseInduction zero succ i.succ) 
goal: Fin.reverseInduction zero succ i.castSucc = succ i (Fin.reverseInduction zero succ i.succ)

full_name: Fin.lastCases
code: /-- Define `f : Π i : Fin n.succ, motive i` by separately handling the cases `i = Fin.last n` and
`i = j.castSucc`, `j : Fin n`. -/
@[elab_as_elim] def lastCases {n : Nat} {motive : Fin (n + 1) → Sort _} (last : motive (Fin.last n))
    (cast : ∀ i : Fin n, motive (castSucc i)) (i : Fin (n + 1)) : motive i 
goal: motive i

full_name: Fin.lastCases_last
code: @[simp] theorem lastCases_last {n : Nat} {motive : Fin (n + 1) → Sort _} {last cast} :
    (Fin.lastCases last cast (Fin.last n) : motive (Fin.last n)) = last 
goal: Fin.lastCases last cast (Fin.last n) = last

full_name: Fin.lastCases_castSucc
code: @[simp] theorem lastCases_castSucc {n : Nat} {motive : Fin (n + 1) → Sort _} {last cast}
    (i : Fin n) : (Fin.lastCases last cast (Fin.castSucc i) : motive (Fin.castSucc i)) = cast i 
goal: Fin.lastCases last cast i.castSucc = cast i

full_name: Fin.addCases
code: /-- Define `f : Π i : Fin (m + n), motive i` by separately handling the cases `i = castAdd n i`,
`j : Fin m` and `i = natAdd m j`, `j : Fin n`. -/
@[elab_as_elim] def addCases {m n : Nat} {motive : Fin (m + n) → Sort u}
    (left : ∀ i, motive (castAdd n i)) (right : ∀ i, motive (natAdd m i))
    (i : Fin (m + n)) : motive i 
goal: motive i

full_name: Fin.addCases_left
code: @[simp] theorem addCases_left {m n : Nat} {motive : Fin (m + n) → Sort _} {left right} (i : Fin m) :
    addCases (motive := motive) left right (Fin.castAdd n i) = left i 
goal: Fin.addCases left right (Fin.castAdd n i) = left i

full_name: Fin.addCases_right
code: @[simp]
theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right} (i : Fin n) :
    addCases (motive := motive) left right (natAdd m i) = right i 
goal: Fin.addCases left right (Fin.natAdd m i) = right i

full_name: Fin.ofNat'_add
code: @[simp] theorem ofNat'_add (x : Nat) (lt : 0 < n) (y : Fin n) :
    Fin.ofNat' x lt + y = Fin.ofNat' (x + y.val) lt 
goal: Fin.ofNat' x lt + y = Fin.ofNat' (x + ↑y) lt

full_name: Fin.add_ofNat'
code: @[simp] theorem add_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
    x + Fin.ofNat' y lt = Fin.ofNat' (x.val + y) lt 
goal: x + Fin.ofNat' y lt = Fin.ofNat' (↑x + y) lt

full_name: Fin.coe_sub
code: protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = ((n - b) + a) % n 
goal: ↑(a - b) = (n - ↑b + ↑a) % n

full_name: Fin.ofNat'_sub
code: @[simp] theorem ofNat'_sub (x : Nat) (lt : 0 < n) (y : Fin n) :
    Fin.ofNat' x lt - y = Fin.ofNat' ((n - y.val) + x) lt 
goal: Fin.ofNat' x lt - y = Fin.ofNat' (n - ↑y + x) lt

full_name: Fin.sub_ofNat'
code: @[simp] theorem sub_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
    x - Fin.ofNat' y lt = Fin.ofNat' ((n - y % n) + x.val) lt 
goal: x - Fin.ofNat' y lt = Fin.ofNat' (n - y % n + ↑x) lt

full_name: _private.«.lake».packages.lean4.src.lean.Init.Data.Fin.Lemmas.0.Nat.mod_eq_sub_of_lt_two_mul
code: private theorem _root_.Nat.mod_eq_sub_of_lt_two_mul {x n} (h₁ : n ≤ x) (h₂ : x < 2 * n) :
    x % n = x - n 
goal: x % n = x - n

full_name: Fin.coe_sub_iff_le
code: theorem coe_sub_iff_le {a b : Fin n} : (↑(a - b) : Nat) = a - b ↔ b ≤ a 
goal: ↑(a - b) = ↑a - ↑b ↔ b ≤ a

full_name: Fin.coe_sub_iff_lt
code: theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b 
goal: ↑(a - b) = n + ↑a - ↑b ↔ a < b

full_name: Fin.val_mul
code: theorem val_mul {n : Nat} : ∀ a b : Fin n, (a * b).val = a.val * b.val % n
  
goal: ↑(a * b) = ↑a * ↑b % n

full_name: Fin.coe_mul
code: theorem coe_mul {n : Nat} : ∀ a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
  
goal: ↑(a * b) = ↑a * ↑b % n

full_name: Fin.mul_one
code: protected theorem mul_one (k : Fin (n + 1)) : k * 1 = k 
goal: k * 1 = k

full_name: Fin.mul_comm
code: protected theorem mul_comm (a b : Fin n) : a * b = b * a 
goal: a * b = b * a

full_name: Fin.«instCommutativeHMul_.lake»
code: instance : Std.Commutative (α := Fin n) (· * ·) 
goal: Std.Commutative fun x x_1 => x * x_1

full_name: Fin.mul_assoc
code: protected theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) 
goal: a * b * c = a * (b * c)

full_name: Fin.«instAssociativeHMul_.lake»
code: instance : Std.Associative (α := Fin n) (· * ·) 
goal: Std.Associative fun x x_1 => x * x_1

full_name: Fin.one_mul
code: protected theorem one_mul (k : Fin (n + 1)) : (1 : Fin (n + 1)) * k = k 
goal: 1 * k = k

full_name: Fin.«instLawfulIdentityHAddNatOfNatHMul_.lake»
code: instance : Std.LawfulIdentity (α := Fin (n + 1)) (· * ·) 1 
goal: Std.LawfulIdentity (fun x x_1 => x * x_1) 1

full_name: Fin.mul_zero
code: protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 
goal: k * 0 = 0

full_name: Fin.zero_mul
code: protected theorem zero_mul (k : Fin (n + 1)) : (0 : Fin (n + 1)) * k = 0 
goal: 0 * k = 0