l3lab/ntp-mathlib huggingface dataset:
instance orderIso_subsingleton : Subsingleton (Fin n ≃o α) :=
  ⟨fun e e' => by
    ext i
    

Proof state:
case h.h
n m : ℕ
α : Type u_1
inst✝ : Preorder α
e e' : Fin n ≃o α
i : Fin n
⊢ e i = e' i

Next tactic:
rw [← e.symm.apply_eq_iff_eq, e.symm_apply_apply, ← e'.trans_apply, ext_iff,
      coe_orderIso_apply]
instance nontrivial {n : ℕ} : Nontrivial (Fin (n + 2)) where
  exists_pair_ne := ⟨0, 1, (ne_iff_vne 0 1).mpr (by 

Proof state:
n✝ m n : ℕ
⊢ ↑0 ≠ ↑1

Next tactic:
simp [val_one, val_zero]
theorem nontrivial_iff_two_le : Nontrivial (Fin n) ↔ 2 ≤ n := by
  

Proof state:
n m : ℕ
⊢ Nontrivial (Fin n) ↔ 2 ≤ n

Next tactic:
rcases n with (_ | _ | n)
theorem nontrivial_iff_two_le : Nontrivial (Fin n) ↔ 2 ≤ n := by
  rcases n with (_ | _ | n) <;>
  

Proof state:
case zero
m : ℕ
⊢ Nontrivial (Fin zero) ↔ 2 ≤ zero

Next tactic:
simp [← Nat.one_eq_succ_zero, Fin.nontrivial, not_nontrivial, Nat.succ_le_iff]
theorem nontrivial_iff_two_le : Nontrivial (Fin n) ↔ 2 ≤ n := by
  rcases n with (_ | _ | n) <;>
  

Proof state:
case succ.zero
m : ℕ
⊢ Nontrivial (Fin (Nat.succ zero)) ↔ 2 ≤ Nat.succ zero

Next tactic:
simp [← Nat.one_eq_succ_zero, Fin.nontrivial, not_nontrivial, Nat.succ_le_iff]
theorem nontrivial_iff_two_le : Nontrivial (Fin n) ↔ 2 ≤ n := by
  rcases n with (_ | _ | n) <;>
  

Proof state:
case succ.succ
m n : ℕ
⊢ Nontrivial (Fin (Nat.succ (Nat.succ n))) ↔ 2 ≤ Nat.succ (Nat.succ n)

Next tactic:
simp [← Nat.one_eq_succ_zero, Fin.nontrivial, not_nontrivial, Nat.succ_le_iff]
instance addCommSemigroup (n : ℕ) : AddCommSemigroup (Fin n) where
  add := (· + ·)
  add_assoc := by 

Proof state:
n✝ m n : ℕ
⊢ ∀ (a b c : Fin n), a + b + c = a + (b + c)

Next tactic:
simp [eq_iff_veq, add_def, add_assoc]
instance addCommSemigroup (n : ℕ) : AddCommSemigroup (Fin n) where
  add := (· + ·)
  add_assoc := by simp [eq_iff_veq, add_def, add_assoc]
  add_comm := by 

Proof state:
n✝ m n : ℕ
⊢ ∀ (a b : Fin n), a + b = b + a

Next tactic:
simp [eq_iff_veq, add_def, add_comm]
protected theorem add_zero [NeZero n] (k : Fin n) : k + 0 = k := by
  

Proof state:
n m : ℕ
inst✝ : NeZero n
k : Fin n
⊢ k + 0 = k

Next tactic:
simp only [add_def, val_zero', add_zero, mod_eq_of_lt (is_lt k)]
protected theorem zero_add [NeZero n] (k : Fin n) : 0 + k = k := by
  

Proof state:
n m : ℕ
inst✝ : NeZero n
k : Fin n
⊢ 0 + k = k

Next tactic:
simp [eq_iff_veq, add_def, mod_eq_of_lt (is_lt k)]
instance inhabitedFinOneAdd (n : ℕ) : Inhabited (Fin (1 + n)) :=
  haveI : NeZero (1 + n) := by 

Proof state:
n✝ m n : ℕ
⊢ NeZero (1 + n)

Next tactic:
rw [Nat.add_comm]
instance inhabitedFinOneAdd (n : ℕ) : Inhabited (Fin (1 + n)) :=
  haveI : NeZero (1 + n) := by rw [Nat.add_comm]; 

Proof state:
n✝ m n : ℕ
⊢ NeZero (n + 1)

Next tactic:
infer_instance
instance (n) : AddCommSemigroup (Fin n) where
  add_assoc := by 

Proof state:
n✝ m n : ℕ
⊢ ∀ (a b c : Fin n), a + b + c = a + (b + c)

Next tactic:
simp [eq_iff_veq, add_def, add_assoc]
instance (n) : AddCommSemigroup (Fin n) where
  add_assoc := by simp [eq_iff_veq, add_def, add_assoc]
  add_comm := by 

Proof state:
n✝ m n : ℕ
⊢ ∀ (a b : Fin n), a + b = b + a

Next tactic:
simp [eq_iff_veq, add_def, add_comm]
theorem val_add_eq_ite {n : ℕ} (a b : Fin n) :
    (↑(a + b) : ℕ) = if n ≤ a + b then a + b - n else a + b := by
  

Proof state:
n✝ m n : ℕ
a b : Fin n
⊢ ↑(a + b) = if n ≤ ↑a + ↑b then ↑a + ↑b - n else ↑a + ↑b

Next tactic:
rw [Fin.val_add, Nat.add_mod_eq_ite, Nat.mod_eq_of_lt (show ↑a < n from a.2),
    Nat.mod_eq_of_lt (show ↑b < n from b.2)]
@[deprecated]
theorem val_bit0 {n : ℕ} (k : Fin n) : ((bit0 k : Fin n) : ℕ) = bit0 (k : ℕ) % n := by
  

Proof state:
n✝ m n : ℕ
k : Fin n
⊢ ↑(bit0 k) = bit0 ↑k % n

Next tactic:
cases k
@[deprecated]
theorem val_bit0 {n : ℕ} (k : Fin n) : ((bit0 k : Fin n) : ℕ) = bit0 (k : ℕ) % n := by
  cases k
  

Proof state:
case mk
n✝ m n val✝ : ℕ
isLt✝ : val✝ < n
⊢ ↑(bit0 { val := val✝, isLt := isLt✝ }) = bit0 ↑{ val := val✝, isLt := isLt✝ } % n

Next tactic:
rfl
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  

Proof state:
n✝ m n : ℕ
inst✝ : NeZero n
k : Fin n
⊢ ↑(bit1 k) = bit1 ↑k % n

Next tactic:
cases n
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  cases n;
  · 

Proof state:
case zero
n m : ℕ
inst✝ : NeZero zero
k : Fin zero
⊢ ↑(bit1 k) = bit1 ↑k % zero

Next tactic:
cases' k with k h
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  cases n;
  · cases' k with k h
    

Proof state:
case zero.mk
n m : ℕ
inst✝ : NeZero zero
k : ℕ
h : k < zero
⊢ ↑(bit1 { val := k, isLt := h }) = bit1 ↑{ val := k, isLt := h } % zero

Next tactic:
cases k
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  cases n;
  · cases' k with k h
    cases k
    · 

Proof state:
case zero.mk.zero
n m : ℕ
inst✝ : NeZero zero
h : zero < zero
⊢ ↑(bit1 { val := zero, isLt := h }) = bit1 ↑{ val := zero, isLt := h } % zero

Next tactic:
show _ % _ = _
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  cases n;
  · cases' k with k h
    cases k
    · show _ % _ = _
      

Proof state:
case zero.mk.zero
n m : ℕ
inst✝ : NeZero zero
h : zero < zero
⊢ ((zero + zero) % zero + 1 % zero) % zero = bit1 ↑{ val := zero, isLt := h } % zero

Next tactic:
simp
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  cases n;
  · cases' k with k h
    cases k
    · show _ % _ = _
      simp
    

Proof state:
case zero.mk.succ
n m : ℕ
inst✝ : NeZero zero
n✝ : ℕ
h : Nat.succ n✝ < zero
⊢ ↑(bit1 { val := Nat.succ n✝, isLt := h }) = bit1 ↑{ val := Nat.succ n✝, isLt := h } % zero

Next tactic:
cases' h with _ h
@[deprecated]
theorem val_bit1 {n : ℕ} [NeZero n] (k : Fin n) :
    ((bit1 k : Fin n) : ℕ) = bit1 (k : ℕ) % n := by
  cases n;
  · cases' k with k h
    cases k
    · show _ % _ = _
      simp
    cases' h with _ h
  

Proof state:
case succ
n m n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
k : Fin (Nat.succ n✝)
⊢ ↑(bit1 k) = bit1 ↑k % Nat.succ n✝

Next tactic:
simp [bit1, Fin.val_bit0, Fin.val_add, Fin.val_one]
@[simp, deprecated]
theorem mk_bit1 {m n : ℕ} [NeZero n] (h : bit1 m < n) :
    (⟨bit1 m, h⟩ : Fin n) =
      (bit1 ⟨m, (Nat.le_add_right m m).trans_lt ((m + m).lt_succ_self.trans h)⟩ : Fin _) := by
  

Proof state:
n✝ m✝ m n : ℕ
inst✝ : NeZero n
h : bit1 m < n
⊢ { val := bit1 m, isLt := h } = bit1 { val := m, isLt := (_ : m < n) }

Next tactic:
ext
@[simp, deprecated]
theorem mk_bit1 {m n : ℕ} [NeZero n] (h : bit1 m < n) :
    (⟨bit1 m, h⟩ : Fin n) =
      (bit1 ⟨m, (Nat.le_add_right m m).trans_lt ((m + m).lt_succ_self.trans h)⟩ : Fin _) := by
  ext
  

Proof state:
case h
n✝ m✝ m n : ℕ
inst✝ : NeZero n
h : bit1 m < n
⊢ ↑{ val := bit1 m, isLt := h } = ↑(bit1 { val := m, isLt := (_ : m < n) })

Next tactic:
simp only [bit1, bit0] at h
@[simp, deprecated]
theorem mk_bit1 {m n : ℕ} [NeZero n] (h : bit1 m < n) :
    (⟨bit1 m, h⟩ : Fin n) =
      (bit1 ⟨m, (Nat.le_add_right m m).trans_lt ((m + m).lt_succ_self.trans h)⟩ : Fin _) := by
  ext
  simp only [bit1, bit0] at h
  

Proof state:
case h
n✝ m✝ m n : ℕ
inst✝ : NeZero n
h : m + m + 1 < n
⊢ ↑{ val := bit1 m, isLt := h } = ↑(bit1 { val := m, isLt := (_ : m < n) })

Next tactic:
simp only [bit1, bit0, val_add, val_one', ← Nat.add_mod, Nat.mod_eq_of_lt h]
@[simp] lemma nat_cast_self (n : ℕ) [NeZero n] : (n : Fin n) = 0 := by 

Proof state:
n✝ m n : ℕ
inst✝ : NeZero n
⊢ ↑n = 0

Next tactic:
ext
@[simp] lemma nat_cast_self (n : ℕ) [NeZero n] : (n : Fin n) = 0 := by ext; 

Proof state:
case h
n✝ m n : ℕ
inst✝ : NeZero n
⊢ ↑↑n = ↑0

Next tactic:
simp
@[simp] lemma nat_cast_eq_zero {a n : ℕ} [NeZero n] : (a : Fin n) = 0 ↔ n ∣ a := by
  

Proof state:
n✝ m a n : ℕ
inst✝ : NeZero n
⊢ ↑a = 0 ↔ n ∣ a

Next tactic:
simp [eq_iff_veq, Nat.dvd_iff_mod_eq_zero]
@[simp]
theorem cast_nat_eq_last (n) : (n : Fin (n + 1)) = Fin.last n := by 

Proof state:
n✝ m n : ℕ
⊢ ↑n = last n

Next tactic:
ext
@[simp]
theorem cast_nat_eq_last (n) : (n : Fin (n + 1)) = Fin.last n := by ext; 

Proof state:
case h
n✝ m n : ℕ
⊢ ↑↑n = ↑(last n)

Next tactic:
simp
theorem le_val_last (i : Fin (n + 1)) : i ≤ n := by
  

Proof state:
n m : ℕ
i : Fin (n + 1)
⊢ i ≤ ↑n

Next tactic:
rw [Fin.cast_nat_eq_last]
theorem le_val_last (i : Fin (n + 1)) : i ≤ n := by
  rw [Fin.cast_nat_eq_last]
  

Proof state:
n m : ℕ
i : Fin (n + 1)
⊢ i ≤ last n

Next tactic:
exact Fin.le_last i
@[simp]
theorem one_eq_zero_iff [NeZero n] : (1 : Fin n) = 0 ↔ n = 1 := by
  

Proof state:
n m : ℕ
inst✝ : NeZero n
⊢ 1 = 0 ↔ n = 1

Next tactic:
rw [← Nat.cast_one, nat_cast_eq_zero, Nat.dvd_one]
@[simp]
theorem zero_eq_one_iff [NeZero n] : (0 : Fin n) = 1 ↔ n = 1 := by 

Proof state:
n m : ℕ
inst✝ : NeZero n
⊢ 0 = 1 ↔ n = 1

Next tactic:
rw [eq_comm, one_eq_zero_iff]
@[simp]
theorem succ_zero_eq_one' [NeZero n] : Fin.succ (0 : Fin n) = 1 := by
  

Proof state:
n m : ℕ
inst✝ : NeZero n
⊢ succ 0 = 1

Next tactic:
cases n
@[simp]
theorem succ_zero_eq_one' [NeZero n] : Fin.succ (0 : Fin n) = 1 := by
  cases n
  · 

Proof state:
case zero
m : ℕ
inst✝ : NeZero zero
⊢ succ 0 = 1

Next tactic:
exact (NeZero.ne 0 rfl).elim
@[simp]
theorem succ_zero_eq_one' [NeZero n] : Fin.succ (0 : Fin n) = 1 := by
  cases n
  · exact (NeZero.ne 0 rfl).elim
  · 

Proof state:
case succ
m n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
⊢ succ 0 = 1

Next tactic:
rfl
/--
The `Fin.succ_one_eq_two` in `Std` only applies in `Fin (n+2)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem succ_one_eq_two' [NeZero n] : Fin.succ (1 : Fin (n + 1)) = 2 := by
  

Proof state:
n m : ℕ
inst✝ : NeZero n
⊢ succ 1 = 2

Next tactic:
cases n
/--
The `Fin.succ_one_eq_two` in `Std` only applies in `Fin (n+2)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem succ_one_eq_two' [NeZero n] : Fin.succ (1 : Fin (n + 1)) = 2 := by
  cases n
  · 

Proof state:
case zero
m : ℕ
inst✝ : NeZero zero
⊢ succ 1 = 2

Next tactic:
exact (NeZero.ne 0 rfl).elim
/--
The `Fin.succ_one_eq_two` in `Std` only applies in `Fin (n+2)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem succ_one_eq_two' [NeZero n] : Fin.succ (1 : Fin (n + 1)) = 2 := by
  cases n
  · exact (NeZero.ne 0 rfl).elim
  · 

Proof state:
case succ
m n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
⊢ succ 1 = 2

Next tactic:
rfl
/--
The `Fin.le_zero_iff` in `Std` only applies in `Fin (n+1)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem le_zero_iff' {n : ℕ} [NeZero n] {k : Fin n} : k ≤ 0 ↔ k = 0 :=
  ⟨fun h => Fin.eq_of_veq $ by 

Proof state:
n✝ m n : ℕ
inst✝ : NeZero n
k : Fin n
h : k ≤ 0
⊢ ↑k = ↑0

Next tactic:
rw [Nat.eq_zero_of_le_zero h]
/--
The `Fin.le_zero_iff` in `Std` only applies in `Fin (n+1)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem le_zero_iff' {n : ℕ} [NeZero n] {k : Fin n} : k ≤ 0 ↔ k = 0 :=
  ⟨fun h => Fin.eq_of_veq $ by rw [Nat.eq_zero_of_le_zero h]; 

Proof state:
n✝ m n : ℕ
inst✝ : NeZero n
k : Fin n
h : k ≤ 0
⊢ 0 = ↑0

Next tactic:
rfl
/--
The `Fin.le_zero_iff` in `Std` only applies in `Fin (n+1)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem le_zero_iff' {n : ℕ} [NeZero n] {k : Fin n} : k ≤ 0 ↔ k = 0 :=
  ⟨fun h => Fin.eq_of_veq $ by rw [Nat.eq_zero_of_le_zero h]; rfl, by 

Proof state:
n✝ m n : ℕ
inst✝ : NeZero n
k : Fin n
⊢ k = 0 → k ≤ 0

Next tactic:
rintro rfl
/--
The `Fin.le_zero_iff` in `Std` only applies in `Fin (n+1)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem le_zero_iff' {n : ℕ} [NeZero n] {k : Fin n} : k ≤ 0 ↔ k = 0 :=
  ⟨fun h => Fin.eq_of_veq $ by rw [Nat.eq_zero_of_le_zero h]; rfl, by rintro rfl; 

Proof state:
n✝ m n : ℕ
inst✝ : NeZero n
⊢ 0 ≤ 0

Next tactic:
exact le_refl _
@[simp]
theorem coe_of_injective_castLEEmb_symm {n k : ℕ} (h : n ≤ k) (i : Fin k) (hi) :
    ((Equiv.ofInjective _ (castLEEmb h).injective).symm ⟨i, hi⟩ : ℕ) = i := by
  

Proof state:
n✝ m n k : ℕ
h : n ≤ k
i : Fin k
hi : i ∈ Set.range ⇑(castLEEmb h)
⊢ ↑((Equiv.ofInjective ⇑(castLEEmb h) (_ : Injective ⇑(castLEEmb h))).symm { val := i, property := hi }) = ↑i

Next tactic:
rw [← coe_castLE h]
@[simp]
theorem coe_of_injective_castLEEmb_symm {n k : ℕ} (h : n ≤ k) (i : Fin k) (hi) :
    ((Equiv.ofInjective _ (castLEEmb h).injective).symm ⟨i, hi⟩ : ℕ) = i := by
  rw [← coe_castLE h]
  

Proof state:
n✝ m n k : ℕ
h : n ≤ k
i : Fin k
hi : i ∈ Set.range ⇑(castLEEmb h)
⊢ ↑(castLE h ((Equiv.ofInjective ⇑(castLEEmb h) (_ : Injective ⇑(castLEEmb h))).symm { val := i, property := hi })) = ↑i

Next tactic:
exact congr_arg Fin.val (Equiv.apply_ofInjective_symm _ _)
@[simp]
theorem symm_castIso (h : n = m) : (castIso h).symm = castIso h.symm := by
  

Proof state:
n m : ℕ
h : n = m
⊢ OrderIso.symm (castIso h) = castIso (_ : m = n)

Next tactic:
simp [eq_iff_true_of_subsingleton]
@[simp]
theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : cast h (0 : Fin n) =
    by 

Proof state:
n m n' : ℕ
inst✝ : NeZero n
h : n = n'
⊢ Fin n'

Next tactic:
{ haveI : NeZero n' := by {rw [← h]; infer_instance}; exact 0}
@[simp]
theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : cast h (0 : Fin n) =
    by { 

Proof state:
n m n' : ℕ
inst✝ : NeZero n
h : n = n'
⊢ Fin n'

Next tactic:
haveI : NeZero n' := by {rw [← h]; infer_instance}
@[simp]
theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : cast h (0 : Fin n) =
    by { haveI : NeZero n' := by 

Proof state:
n m n' : ℕ
inst✝ : NeZero n
h : n = n'
⊢ NeZero n'

Next tactic:
{rw [← h]; infer_instance}
@[simp]
theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : cast h (0 : Fin n) =
    by { haveI : NeZero n' := by {

Proof state:
n m n' : ℕ
inst✝ : NeZero n
h : n = n'
⊢ NeZero n'

Next tactic:
rw [← h]
@[simp]
theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : cast h (0 : Fin n) =
    by { haveI : NeZero n' := by {rw [← h]; 

Proof state:
n m n' : ℕ
inst✝ : NeZero n
h : n = n'
⊢ NeZero n

Next tactic:
infer_instance
@[simp]
theorem cast_zero {n' : ℕ} [NeZero n] {h : n = n'} : cast h (0 : Fin n) =
    by { haveI : NeZero n' := by {rw [← h]; infer_instance}; 

Proof state:
n m n' : ℕ
inst✝ : NeZero n
h : n = n'
this : NeZero n'
⊢ Fin n'

Next tactic:
exact 0
@[simp]
theorem castIso_refl (h : n = n := rfl) : castIso h = OrderIso.refl (Fin n) := by
  

Proof state:
n m : ℕ
h : optParam (n = n) (_ : n = n)
⊢ castIso h = OrderIso.refl (Fin n)

Next tactic:
ext
@[simp]
theorem castIso_refl (h : n = n := rfl) : castIso h = OrderIso.refl (Fin n) := by
  ext
  

Proof state:
case h.h.h
n m : ℕ
h : optParam (n = n) (_ : n = n)
x✝ : Fin n
⊢ ↑((castIso h) x✝) = ↑((OrderIso.refl (Fin n)) x✝)

Next tactic:
simp
/-- While in many cases `Fin.castIso` is better than `Equiv.cast`/`cast`, sometimes we want to apply
a generic theorem about `cast`. -/
theorem castIso_to_equiv (h : n = m) : (castIso h).toEquiv = Equiv.cast (h ▸ rfl) := by
  

Proof state:
n m : ℕ
h : n = m
⊢ (castIso h).toEquiv = Equiv.cast (_ : Fin n = Fin m)

Next tactic:
subst h
/-- While in many cases `Fin.castIso` is better than `Equiv.cast`/`cast`, sometimes we want to apply
a generic theorem about `cast`. -/
theorem castIso_to_equiv (h : n = m) : (castIso h).toEquiv = Equiv.cast (h ▸ rfl) := by
  subst h
  

Proof state:
n : ℕ
⊢ (castIso (_ : n = n)).toEquiv = Equiv.cast (_ : Fin n = Fin n)

Next tactic:
simp
/-- While in many cases `Fin.cast` is better than `Equiv.cast`/`cast`, sometimes we want to apply
a generic theorem about `cast`. -/
theorem cast_eq_cast (h : n = m) : (cast h : Fin n → Fin m) = _root_.cast (h ▸ rfl) := by
  

Proof state:
n m : ℕ
h : n = m
⊢ cast h = _root_.cast (_ : Fin n = Fin m)

Next tactic:
subst h
/-- While in many cases `Fin.cast` is better than `Equiv.cast`/`cast`, sometimes we want to apply
a generic theorem about `cast`. -/
theorem cast_eq_cast (h : n = m) : (cast h : Fin n → Fin m) = _root_.cast (h ▸ rfl) := by
  subst h
  

Proof state:
n : ℕ
⊢ cast (_ : n = n) = _root_.cast (_ : Fin n = Fin n)

Next tactic:
ext
/-- While in many cases `Fin.cast` is better than `Equiv.cast`/`cast`, sometimes we want to apply
a generic theorem about `cast`. -/
theorem cast_eq_cast (h : n = m) : (cast h : Fin n → Fin m) = _root_.cast (h ▸ rfl) := by
  subst h
  ext
  

Proof state:
case h.h
n : ℕ
x✝ : Fin n
⊢ ↑(cast (_ : n = n) x✝) = ↑(_root_.cast (_ : Fin n = Fin n) x✝)

Next tactic:
rfl
/-- `castSucc i` is positive when `i` is positive.

The `Fin.castSucc_pos` in `Std` only applies in `Fin (n+1)`.
This one instead uses a `NeZero n` typeclass hypothesis.-/
theorem castSucc_pos' [NeZero n] {i : Fin n} (h : 0 < i) : 0 < castSucc i := by
  

Proof state:
n m : ℕ
inst✝ : NeZero n
i : Fin n
h : 0 < i
⊢ 0 < castSucc i

Next tactic:
simpa [lt_iff_val_lt_val] using h
/--
The `Fin.castSucc_eq_zero_iff` in `Std` only applies in `Fin (n+1)`.
This one instead uses a `NeZero n` typeclass hypothesis.
-/
@[simp]
theorem castSucc_eq_zero_iff' [NeZero n] (a : Fin n) : castSucc a = 0 ↔ a = 0 :=
  Fin.ext_iff.trans <| (Fin.ext_iff.trans <| by 

Proof state:
n m : ℕ
inst✝ : NeZero n
a : Fin n
⊢ ↑a = ↑0 ↔ ↑(castSucc a) = ↑0

Next tactic:
simp
@[norm_cast, simp]
theorem coe_eq_castSucc {a : Fin n} : (a : Fin (n + 1)) = castSucc a := by
  

Proof state:
n m : ℕ
a : Fin n
⊢ ↑↑a = castSucc a

Next tactic:
ext
@[norm_cast, simp]
theorem coe_eq_castSucc {a : Fin n} : (a : Fin (n + 1)) = castSucc a := by
  ext
  

Proof state:
case h
n m : ℕ
a : Fin n
⊢ ↑↑↑a = ↑(castSucc a)

Next tactic:
exact val_cast_of_lt (Nat.lt.step a.is_lt)
@[simp]
theorem coe_of_injective_castSucc_symm {n : ℕ} (i : Fin n.succ) (hi) :
    ((Equiv.ofInjective castSucc (castSucc_injective _)).symm ⟨i, hi⟩ : ℕ) = i := by
  

Proof state:
n✝ m n : ℕ
i : Fin (Nat.succ n)
hi : i ∈ Set.range castSucc
⊢ ↑((Equiv.ofInjective castSucc (_ : Injective castSucc)).symm { val := i, property := hi }) = ↑i

Next tactic:
rw [← coe_castSucc]
@[simp]
theorem coe_of_injective_castSucc_symm {n : ℕ} (i : Fin n.succ) (hi) :
    ((Equiv.ofInjective castSucc (castSucc_injective _)).symm ⟨i, hi⟩ : ℕ) = i := by
  rw [← coe_castSucc]
  

Proof state:
n✝ m n : ℕ
i : Fin (Nat.succ n)
hi : i ∈ Set.range castSucc
⊢ ↑(castSucc ((Equiv.ofInjective castSucc (_ : Injective castSucc)).symm { val := i, property := hi })) = ↑i

Next tactic:
exact congr_arg val (Equiv.apply_ofInjective_symm _ _)
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  

Proof state:
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
⊢ ((fun x x_1 => x < x_1) ⇒ r) f f ↔ ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))

Next tactic:
constructor
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · 

Proof state:
case mp
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
⊢ ((fun x x_1 => x < x_1) ⇒ r) f f → ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))

Next tactic:
intro H i
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    

Proof state:
case mp
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ((fun x x_1 => x < x_1) ⇒ r) f f
i : Fin n
⊢ r (f (castSucc i)) (f (succ i))

Next tactic:
exact H i.castSucc_lt_succ
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    exact H i.castSucc_lt_succ
  · 

Proof state:
case mpr
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
⊢ (∀ (i : Fin n), r (f (castSucc i)) (f (succ i))) → ((fun x x_1 => x < x_1) ⇒ r) f f

Next tactic:
refine' fun H i => Fin.induction _ _
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    exact H i.castSucc_lt_succ
  · refine' fun H i => Fin.induction _ _
    · 

Proof state:
case mpr.refine'_1
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))
i : Fin (n + 1)
⊢ (fun x x_1 => x < x_1) i 0 → r (f i) (f 0)

Next tactic:
exact fun h => (h.not_le (zero_le i)).elim
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    exact H i.castSucc_lt_succ
  · refine' fun H i => Fin.induction _ _
    · exact fun h => (h.not_le (zero_le i)).elim
    · 

Proof state:
case mpr.refine'_2
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))
i : Fin (n + 1)
⊢ ∀ (i_1 : Fin n),
    ((fun x x_1 => x < x_1) i (castSucc i_1) → r (f i) (f (castSucc i_1))) →
      (fun x x_1 => x < x_1) i (succ i_1) → r (f i) (f (succ i_1))

Next tactic:
intro j ihj hij
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    exact H i.castSucc_lt_succ
  · refine' fun H i => Fin.induction _ _
    · exact fun h => (h.not_le (zero_le i)).elim
    · intro j ihj hij
      

Proof state:
case mpr.refine'_2
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))
i : Fin (n + 1)
j : Fin n
ihj : (fun x x_1 => x < x_1) i (castSucc j) → r (f i) (f (castSucc j))
hij : i < succ j
⊢ r (f i) (f (succ j))

Next tactic:
rw [← le_castSucc_iff] at hij
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    exact H i.castSucc_lt_succ
  · refine' fun H i => Fin.induction _ _
    · exact fun h => (h.not_le (zero_le i)).elim
    · intro j ihj hij
      rw [← le_castSucc_iff] at hij
      

Proof state:
case mpr.refine'_2
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))
i : Fin (n + 1)
j : Fin n
ihj : (fun x x_1 => x < x_1) i (castSucc j) → r (f i) (f (castSucc j))
hij : i ≤ castSucc j
⊢ r (f i) (f (succ j))

Next tactic:
rcases hij.eq_or_lt with (rfl | hlt)
theorem liftFun_iff_succ {α : Type*} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} :
    ((· < ·) ⇒ r) f f ↔ ∀ i : Fin n, r (f (castSucc i)) (f i.succ) := by
  constructor
  · intro H i
    exact H i.castSucc_lt_succ
  · refine' fun H i => Fin.induction _ _
    · exact fun h => (h.not_le (zero_le i)).elim
    · intro j ihj hij
      rw [← le_castSucc_iff] at hij
      rcases hij.eq_or_lt with (rfl | hlt)
      

Proof state:
case mpr.refine'_2.inl
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))
j : Fin n
ihj : (fun x x_1 => x < x_1) (castSucc j) (castSucc j) → r (f (castSucc j)) (f (castSucc j))
hij : castSucc j ≤ castSucc j
⊢ r (f (castSucc j)) (f (succ j))
case mpr.refine'_2.inr
n m : ℕ
α : Type u_1
r : α → α → Prop
inst✝ : IsTrans α r
f : Fin (n + 1) → α
H : ∀ (i : Fin n), r (f (castSucc i)) (f (succ i))
i : Fin (n + 1)
j : Fin n
ihj : (fun x x_1 => x < x_1) i (castSucc j) → r (f i) (f (castSucc j))
hij : i ≤ castSucc j
hlt : i < castSucc j
⊢ r (f i) (f (succ j))

Next tactic:
exacts [H j, _root_.trans (ihj hlt) (H j)]