l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
  | ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
    rw [birthday_def, nadd_def]
    -- Porting note: `simp` doesn't apply
    erw [lsub_sum, lsub_sum]
    simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
      mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
    -- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
    -- `termination_by`. Use a workaround.
    conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => left; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yL b)]
    conv_lhs => right; left; right; intro a; rw [birthday_add (xR a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => right; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yR b)]
    rw [max_max_max_comm]
    congr <;> apply le_antisymm
    any_goals
      exact
        max_le_iff.2
          ⟨lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveLeft_lt _),
            lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveRight_lt _)⟩
    all_goals
      

Proof state:
case e_a.a
a b x : PGame
xl xr : Type u
xL : xl → PGame
xR : xr → PGame
yl yr : Type u
yL : yl → PGame
yR : yr → PGame
⊢ (blsub (birthday (mk yl yr yL yR)) fun b' x => birthday (mk xl xr xL xR) ♯ b') ≤
    max (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yL b))
      (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yR b))

Next tactic:
refine blsub_le_iff.2 fun i hi => ?_
@[simp]
theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
  | ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
    rw [birthday_def, nadd_def]
    -- Porting note: `simp` doesn't apply
    erw [lsub_sum, lsub_sum]
    simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
      mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
    -- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
    -- `termination_by`. Use a workaround.
    conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => left; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yL b)]
    conv_lhs => right; left; right; intro a; rw [birthday_add (xR a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => right; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yR b)]
    rw [max_max_max_comm]
    congr <;> apply le_antisymm
    any_goals
      exact
        max_le_iff.2
          ⟨lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveLeft_lt _),
            lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveRight_lt _)⟩
    all_goals
      refine blsub_le_iff.2 fun i hi => ?_
      

Proof state:
case e_a.a
a b x : PGame
xl xr : Type u
xL : xl → PGame
xR : xr → PGame
yl yr : Type u
yL : yl → PGame
yR : yr → PGame
i : Ordinal.{u}
hi : i < birthday (mk yl yr yL yR)
⊢ birthday (mk xl xr xL xR) ♯ i <
    max (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yL b))
      (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yR b))

Next tactic:
rcases lt_birthday_iff.1 hi with (⟨j, hj⟩ | ⟨j, hj⟩)
@[simp]
theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
  | ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
    rw [birthday_def, nadd_def]
    -- Porting note: `simp` doesn't apply
    erw [lsub_sum, lsub_sum]
    simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
      mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
    -- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
    -- `termination_by`. Use a workaround.
    conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => left; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yL b)]
    conv_lhs => right; left; right; intro a; rw [birthday_add (xR a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => right; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yR b)]
    rw [max_max_max_comm]
    congr <;> apply le_antisymm
    any_goals
      exact
        max_le_iff.2
          ⟨lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveLeft_lt _),
            lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveRight_lt _)⟩
    all_goals
      refine blsub_le_iff.2 fun i hi => ?_
      rcases lt_birthday_iff.1 hi with (⟨j, hj⟩ | ⟨j, hj⟩)
    · 

Proof state:
case e_a.a.inl.intro
a b x : PGame
xl xr : Type u
xL : xl → PGame
xR : xr → PGame
yl yr : Type u
yL : yl → PGame
yR : yr → PGame
i : Ordinal.{u}
hi : i < birthday (mk xl xr xL xR)
j : LeftMoves (mk xl xr xL xR)
hj : i ≤ birthday (moveLeft (mk xl xr xL xR) j)
⊢ i ♯ birthday (mk yl yr yL yR) <
    max (lsub fun a => birthday (xL a) ♯ birthday (mk yl yr yL yR))
      (lsub fun a => birthday (xR a) ♯ birthday (mk yl yr yL yR))

Next tactic:
exact lt_max_of_lt_left ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
@[simp]
theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
  | ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
    rw [birthday_def, nadd_def]
    -- Porting note: `simp` doesn't apply
    erw [lsub_sum, lsub_sum]
    simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
      mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
    -- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
    -- `termination_by`. Use a workaround.
    conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => left; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yL b)]
    conv_lhs => right; left; right; intro a; rw [birthday_add (xR a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => right; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yR b)]
    rw [max_max_max_comm]
    congr <;> apply le_antisymm
    any_goals
      exact
        max_le_iff.2
          ⟨lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveLeft_lt _),
            lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveRight_lt _)⟩
    all_goals
      refine blsub_le_iff.2 fun i hi => ?_
      rcases lt_birthday_iff.1 hi with (⟨j, hj⟩ | ⟨j, hj⟩)
    · exact lt_max_of_lt_left ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
    · 

Proof state:
case e_a.a.inr.intro
a b x : PGame
xl xr : Type u
xL : xl → PGame
xR : xr → PGame
yl yr : Type u
yL : yl → PGame
yR : yr → PGame
i : Ordinal.{u}
hi : i < birthday (mk xl xr xL xR)
j : RightMoves (mk xl xr xL xR)
hj : i ≤ birthday (moveRight (mk xl xr xL xR) j)
⊢ i ♯ birthday (mk yl yr yL yR) <
    max (lsub fun a => birthday (xL a) ♯ birthday (mk yl yr yL yR))
      (lsub fun a => birthday (xR a) ♯ birthday (mk yl yr yL yR))

Next tactic:
exact lt_max_of_lt_right ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
@[simp]
theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
  | ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
    rw [birthday_def, nadd_def]
    -- Porting note: `simp` doesn't apply
    erw [lsub_sum, lsub_sum]
    simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
      mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
    -- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
    -- `termination_by`. Use a workaround.
    conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => left; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yL b)]
    conv_lhs => right; left; right; intro a; rw [birthday_add (xR a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => right; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yR b)]
    rw [max_max_max_comm]
    congr <;> apply le_antisymm
    any_goals
      exact
        max_le_iff.2
          ⟨lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveLeft_lt _),
            lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveRight_lt _)⟩
    all_goals
      refine blsub_le_iff.2 fun i hi => ?_
      rcases lt_birthday_iff.1 hi with (⟨j, hj⟩ | ⟨j, hj⟩)
    · exact lt_max_of_lt_left ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
    · exact lt_max_of_lt_right ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
    · 

Proof state:
case e_a.a.inl.intro
a b x : PGame
xl xr : Type u
xL : xl → PGame
xR : xr → PGame
yl yr : Type u
yL : yl → PGame
yR : yr → PGame
i : Ordinal.{u}
hi : i < birthday (mk yl yr yL yR)
j : LeftMoves (mk yl yr yL yR)
hj : i ≤ birthday (moveLeft (mk yl yr yL yR) j)
⊢ birthday (mk xl xr xL xR) ♯ i <
    max (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yL b))
      (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yR b))

Next tactic:
exact lt_max_of_lt_left ((nadd_le_nadd_left hj _).trans_lt (lt_lsub _ _))
@[simp]
theorem birthday_add : ∀ x y : PGame.{u}, (x + y).birthday = x.birthday ♯ y.birthday
  | ⟨xl, xr, xL, xR⟩, ⟨yl, yr, yL, yR⟩ => by
    rw [birthday_def, nadd_def]
    -- Porting note: `simp` doesn't apply
    erw [lsub_sum, lsub_sum]
    simp only [lsub_sum, mk_add_moveLeft_inl, moveLeft_mk, mk_add_moveLeft_inr,
      mk_add_moveRight_inl, moveRight_mk, mk_add_moveRight_inr]
    -- Porting note: Originally `simp only [birthday_add]`, but this causes an error in
    -- `termination_by`. Use a workaround.
    conv_lhs => left; left; right; intro a; rw [birthday_add (xL a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => left; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yL b)]
    conv_lhs => right; left; right; intro a; rw [birthday_add (xR a) ⟨yl, yr, yL, yR⟩]
    conv_lhs => right; right; right; intro b; rw [birthday_add ⟨xl, xr, xL, xR⟩ (yR b)]
    rw [max_max_max_comm]
    congr <;> apply le_antisymm
    any_goals
      exact
        max_le_iff.2
          ⟨lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveLeft_lt _),
            lsub_le_iff.2 fun i => lt_blsub _ _ (birthday_moveRight_lt _)⟩
    all_goals
      refine blsub_le_iff.2 fun i hi => ?_
      rcases lt_birthday_iff.1 hi with (⟨j, hj⟩ | ⟨j, hj⟩)
    · exact lt_max_of_lt_left ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
    · exact lt_max_of_lt_right ((nadd_le_nadd_right hj _).trans_lt (lt_lsub _ _))
    · exact lt_max_of_lt_left ((nadd_le_nadd_left hj _).trans_lt (lt_lsub _ _))
    · 

Proof state:
case e_a.a.inr.intro
a b x : PGame
xl xr : Type u
xL : xl → PGame
xR : xr → PGame
yl yr : Type u
yL : yl → PGame
yR : yr → PGame
i : Ordinal.{u}
hi : i < birthday (mk yl yr yL yR)
j : RightMoves (mk yl yr yL yR)
hj : i ≤ birthday (moveRight (mk yl yr yL yR) j)
⊢ birthday (mk xl xr xL xR) ♯ i <
    max (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yL b))
      (lsub fun b => birthday (mk xl xr xL xR) ♯ birthday (yR b))

Next tactic:
exact lt_max_of_lt_right ((nadd_le_nadd_left hj _).trans_lt (lt_lsub _ _))
theorem birthday_add_zero : (a + 0).birthday = a.birthday := by 

Proof state:
a b x : PGame
⊢ birthday (a + 0) = birthday a

Next tactic:
simp
theorem birthday_zero_add : (0 + a).birthday = a.birthday := by 

Proof state:
a b x : PGame
⊢ birthday (0 + a) = birthday a

Next tactic:
simp
theorem birthday_add_one : (a + 1).birthday = Order.succ a.birthday := by 

Proof state:
a b x : PGame
⊢ birthday (a + 1) = Order.succ (birthday a)

Next tactic:
simp
theorem birthday_one_add : (1 + a).birthday = Order.succ a.birthday := by 

Proof state:
a b x : PGame
⊢ birthday (1 + a) = Order.succ (birthday a)

Next tactic:
simp
@[simp]
theorem birthday_nat_cast : ∀ n : ℕ, birthday n = n
  | 0 => birthday_zero
  | n + 1 => by 

Proof state:
a b x : PGame
n : ℕ
⊢ birthday ↑(n + 1) = ↑(n + 1)

Next tactic:
simp [birthday_nat_cast]
theorem birthday_add_nat (n : ℕ) : (a + n).birthday = a.birthday + n := by 

Proof state:
a b x : PGame
n : ℕ
⊢ birthday (a + ↑n) = birthday a + ↑n

Next tactic:
simp
theorem birthday_nat_add (n : ℕ) : (↑n + a).birthday = a.birthday + n := by 

Proof state:
a b x : PGame
n : ℕ
⊢ birthday (↑n + a) = birthday a + ↑n

Next tactic:
simp
lemma ne_zero [CharZero R] : (P.root i : M) ≠ 0 :=
  fun h ↦ by 

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i : ι
inst✝ : CharZero R
h : P.root i = 0
⊢ False

Next tactic:
simpa [h] using P.root_coroot_two i
lemma ne_zero' [CharZero R] : (P.coroot i : N) ≠ 0 :=
  fun h ↦ by 

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i : ι
inst✝ : CharZero R
h : P.coroot i = 0
⊢ False

Next tactic:
simpa [h] using P.root_coroot_two i
lemma coroot_root_two :
    (P.toLin.flip (P.coroot i)) (P.root i) = 2 := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁵ : _root_.Finite ι
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
P : RootPairing ι R M N
i : ι
⊢ ((LinearMap.flip P.toLin) (P.coroot i)) (P.root i) = 2

Next tactic:
rw [LinearMap.flip_apply, P.root_coroot_two i]
lemma reflection_dualMap_eq_coreflection :
    (P.reflection i).dualMap ∘ₗ P.toLin.flip = P.toLin.flip ∘ₗ P.coreflection i := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁵ : _root_.Finite ι
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
P : RootPairing ι R M N
i : ι
⊢ ↑(LinearEquiv.dualMap (reflection P i)) ∘ₗ LinearMap.flip P.toLin = LinearMap.flip P.toLin ∘ₗ ↑(coreflection P i)

Next tactic:
ext n m
lemma reflection_dualMap_eq_coreflection :
    (P.reflection i).dualMap ∘ₗ P.toLin.flip = P.toLin.flip ∘ₗ P.coreflection i := by
  ext n m
  

Proof state:
case h.h
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁵ : _root_.Finite ι
inst✝⁴ : CommRing R
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
P : RootPairing ι R M N
i : ι
n : N
m : M
⊢ ((↑(LinearEquiv.dualMap (reflection P i)) ∘ₗ LinearMap.flip P.toLin) n) m =
    ((LinearMap.flip P.toLin ∘ₗ ↑(coreflection P i)) n) m

Next tactic:
simp [coreflection_apply, reflection_apply, mul_comm (P.toLin m (P.coroot i))]
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
⊢ i = j

Next tactic:
set α := P.root i
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
⊢ i = j

Next tactic:
set β := P.root j
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  set β := P.root j
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
β : M := P.root j
⊢ i = j

Next tactic:
set sα : M ≃ₗ[R] M := P.reflection i
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  set β := P.root j
  set sα : M ≃ₗ[R] M := P.reflection i
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
β : M := P.root j
sα : M ≃ₗ[R] M := reflection P i
⊢ i = j

Next tactic:
set sβ : M ≃ₗ[R] M := P.reflection j
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  set β := P.root j
  set sα : M ≃ₗ[R] M := P.reflection i
  set sβ : M ≃ₗ[R] M := P.reflection j
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
β : M := P.root j
sα : M ≃ₗ[R] M := reflection P i
sβ : M ≃ₗ[R] M := reflection P j
⊢ i = j

Next tactic:
set sαβ : M ≃ₗ[R] M := sβ.trans sα
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  set β := P.root j
  set sα : M ≃ₗ[R] M := P.reflection i
  set sβ : M ≃ₗ[R] M := P.reflection j
  set sαβ : M ≃ₗ[R] M := sβ.trans sα
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
β : M := P.root j
sα : M ≃ₗ[R] M := reflection P i
sβ : M ≃ₗ[R] M := reflection P j
sαβ : M ≃ₗ[R] M := sβ ≪≫ₗ sα
⊢ i = j

Next tactic:
have hα : sα β = β - (2 : R) • α := by rw [P.reflection_apply, h j, P.root_coroot_two j]
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  set β := P.root j
  set sα : M ≃ₗ[R] M := P.reflection i
  set sβ : M ≃ₗ[R] M := P.reflection j
  set sαβ : M ≃ₗ[R] M := sβ.trans sα
  have hα : sα β = β - (2 : R) • α := by 

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
β : M := P.root j
sα : M ≃ₗ[R] M := reflection P i
sβ : M ≃ₗ[R] M := reflection P j
sαβ : M ≃ₗ[R] M := sβ ≪≫ₗ sα
⊢ sα β = β - 2 • α

Next tactic:
rw [P.reflection_apply, h j, P.root_coroot_two j]
/-- Even though the roots may not span, coroots are distinguished by their pairing with the
roots. The proof depends crucially on the fact that there are finitely-many roots.

Modulo trivial generalisations, this statement is exactly Lemma 1.1.4 on page 87 of SGA 3 XXI.
See also `RootPairing.injOn_dualMap_subtype_span_root_coroot` for a more useful restatement. -/
lemma eq_of_forall_coroot_root_eq [NoZeroSMulDivisors ℤ M] (i j : ι)
    (h : ∀ k, P.toLin (P.root k) (P.coroot i) = P.toLin (P.root k) (P.coroot j)) :
    i = j := by
  set α := P.root i
  set β := P.root j
  set sα : M ≃ₗ[R] M := P.reflection i
  set sβ : M ≃ₗ[R] M := P.reflection j
  set sαβ : M ≃ₗ[R] M := sβ.trans sα
  have hα : sα β = β - (2 : R) • α := by rw [P.reflection_apply, h j, P.root_coroot_two j]
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
N : Type u_4
inst✝⁶ : _root_.Finite ι
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
inst✝² : AddCommGroup N
inst✝¹ : Module R N
P : RootPairing ι R M N
i✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
h : ∀ (k : ι), (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)
α : M := P.root i
β : M := P.root j
sα : M ≃ₗ[R] M := reflection P i
sβ : M ≃ₗ[R] M := reflection P j
sαβ : M ≃ₗ[R] M := sβ ≪≫ₗ sα
hα : sα β = β - 2 • α
⊢ i = j

Next tactic:
have hβ : sβ α = α - (2 : R) • β := by rw [P.reflection_apply, ← h i, P.root_coroot_two i]