l3lab/ntp-mathlib huggingface dataset:
/-- 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]
  have hβ : sβ α = α - (2 : R) • β := by rw [P.reflection_apply, ← h i, P.root_coroot_two i]
  have hb : BijOn sαβ (range P.root) (range P.root) :=
    (P.bijOn_reflection_root i).comp (P.bijOn_reflection_root j)
  set f : ℕ → M := fun n ↦ β + (2 * n : ℤ) • (α - β)
  have hf : ∀ n : ℕ, (sαβ^[n]) β = f n := by
    intro n
    induction' n with n ih; simp
    simp only [iterate_succ', ih, hα, hβ, two_smul, smul_add, mul_add, add_smul, comp_apply,
      map_zsmul, zsmul_sub, map_add, neg_sub, map_neg, smul_neg, map_sub, Nat.cast_succ, mul_one,
      LinearEquiv.trans_apply, reflection_apply_self]
    abel
  set f' : ℕ → range P.root := fun n ↦ ⟨f n, by
    rw [← IsFixedPt.image_iterate hb.image_eq n, ← hf]; exact mem_image_of_mem _ (mem_range_self 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 • α
hβ : sβ α = α - 2 • β
hb : BijOn (⇑sαβ) (range ⇑P.root) (range ⇑P.root)
f : ℕ → M := fun n => β + (2 * ↑n) • (α - β)
hf : ∀ (n : ℕ), (⇑sαβ)^[n] β = f n
f' : ℕ → ↑(range ⇑P.root) := fun n => { val := f n, property := (_ : f n ∈ range ⇑P.root) }
⊢ i = j

Next tactic:
have : ¬ Injective f' := not_injective_infinite_finite f'
/-- 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]
  have hβ : sβ α = α - (2 : R) • β := by rw [P.reflection_apply, ← h i, P.root_coroot_two i]
  have hb : BijOn sαβ (range P.root) (range P.root) :=
    (P.bijOn_reflection_root i).comp (P.bijOn_reflection_root j)
  set f : ℕ → M := fun n ↦ β + (2 * n : ℤ) • (α - β)
  have hf : ∀ n : ℕ, (sαβ^[n]) β = f n := by
    intro n
    induction' n with n ih; simp
    simp only [iterate_succ', ih, hα, hβ, two_smul, smul_add, mul_add, add_smul, comp_apply,
      map_zsmul, zsmul_sub, map_add, neg_sub, map_neg, smul_neg, map_sub, Nat.cast_succ, mul_one,
      LinearEquiv.trans_apply, reflection_apply_self]
    abel
  set f' : ℕ → range P.root := fun n ↦ ⟨f n, by
    rw [← IsFixedPt.image_iterate hb.image_eq n, ← hf]; exact mem_image_of_mem _ (mem_range_self j)⟩
  have : ¬ Injective f' := not_injective_infinite_finite f'
  

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 • α
hβ : sβ α = α - 2 • β
hb : BijOn (⇑sαβ) (range ⇑P.root) (range ⇑P.root)
f : ℕ → M := fun n => β + (2 * ↑n) • (α - β)
hf : ∀ (n : ℕ), (⇑sαβ)^[n] β = f n
f' : ℕ → ↑(range ⇑P.root) := fun n => { val := f n, property := (_ : f n ∈ range ⇑P.root) }
this : ¬Injective f'
⊢ i = j

Next tactic:
contrapose! this
/-- 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]
  have hβ : sβ α = α - (2 : R) • β := by rw [P.reflection_apply, ← h i, P.root_coroot_two i]
  have hb : BijOn sαβ (range P.root) (range P.root) :=
    (P.bijOn_reflection_root i).comp (P.bijOn_reflection_root j)
  set f : ℕ → M := fun n ↦ β + (2 * n : ℤ) • (α - β)
  have hf : ∀ n : ℕ, (sαβ^[n]) β = f n := by
    intro n
    induction' n with n ih; simp
    simp only [iterate_succ', ih, hα, hβ, two_smul, smul_add, mul_add, add_smul, comp_apply,
      map_zsmul, zsmul_sub, map_add, neg_sub, map_neg, smul_neg, map_sub, Nat.cast_succ, mul_one,
      LinearEquiv.trans_apply, reflection_apply_self]
    abel
  set f' : ℕ → range P.root := fun n ↦ ⟨f n, by
    rw [← IsFixedPt.image_iterate hb.image_eq n, ← hf]; exact mem_image_of_mem _ (mem_range_self j)⟩
  have : ¬ Injective f' := not_injective_infinite_finite f'
  contrapose! this
  

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 • α
hβ : sβ α = α - 2 • β
hb : BijOn (⇑sαβ) (range ⇑P.root) (range ⇑P.root)
f : ℕ → M := fun n => β + (2 * ↑n) • (α - β)
hf : ∀ (n : ℕ), (⇑sαβ)^[n] β = f n
f' : ℕ → ↑(range ⇑P.root) := fun n => { val := f n, property := (_ : f n ∈ range ⇑P.root) }
this : i ≠ j
⊢ Injective f'

Next tactic:
intros n m hnm
/-- 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]
  have hβ : sβ α = α - (2 : R) • β := by rw [P.reflection_apply, ← h i, P.root_coroot_two i]
  have hb : BijOn sαβ (range P.root) (range P.root) :=
    (P.bijOn_reflection_root i).comp (P.bijOn_reflection_root j)
  set f : ℕ → M := fun n ↦ β + (2 * n : ℤ) • (α - β)
  have hf : ∀ n : ℕ, (sαβ^[n]) β = f n := by
    intro n
    induction' n with n ih; simp
    simp only [iterate_succ', ih, hα, hβ, two_smul, smul_add, mul_add, add_smul, comp_apply,
      map_zsmul, zsmul_sub, map_add, neg_sub, map_neg, smul_neg, map_sub, Nat.cast_succ, mul_one,
      LinearEquiv.trans_apply, reflection_apply_self]
    abel
  set f' : ℕ → range P.root := fun n ↦ ⟨f n, by
    rw [← IsFixedPt.image_iterate hb.image_eq n, ← hf]; exact mem_image_of_mem _ (mem_range_self j)⟩
  have : ¬ Injective f' := not_injective_infinite_finite f'
  contrapose! this
  intros n m hnm
  

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 • α
hβ : sβ α = α - 2 • β
hb : BijOn (⇑sαβ) (range ⇑P.root) (range ⇑P.root)
f : ℕ → M := fun n => β + (2 * ↑n) • (α - β)
hf : ∀ (n : ℕ), (⇑sαβ)^[n] β = f n
f' : ℕ → ↑(range ⇑P.root) := fun n => { val := f n, property := (_ : f n ∈ range ⇑P.root) }
this : i ≠ j
n m : ℕ
hnm : f' n = f' m
⊢ n = m

Next tactic:
rw [Subtype.mk_eq_mk, add_right_inj, ← sub_eq_zero, ← sub_smul, smul_eq_zero, sub_eq_zero,
    sub_eq_zero] at hnm
/-- 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]
  have hβ : sβ α = α - (2 : R) • β := by rw [P.reflection_apply, ← h i, P.root_coroot_two i]
  have hb : BijOn sαβ (range P.root) (range P.root) :=
    (P.bijOn_reflection_root i).comp (P.bijOn_reflection_root j)
  set f : ℕ → M := fun n ↦ β + (2 * n : ℤ) • (α - β)
  have hf : ∀ n : ℕ, (sαβ^[n]) β = f n := by
    intro n
    induction' n with n ih; simp
    simp only [iterate_succ', ih, hα, hβ, two_smul, smul_add, mul_add, add_smul, comp_apply,
      map_zsmul, zsmul_sub, map_add, neg_sub, map_neg, smul_neg, map_sub, Nat.cast_succ, mul_one,
      LinearEquiv.trans_apply, reflection_apply_self]
    abel
  set f' : ℕ → range P.root := fun n ↦ ⟨f n, by
    rw [← IsFixedPt.image_iterate hb.image_eq n, ← hf]; exact mem_image_of_mem _ (mem_range_self j)⟩
  have : ¬ Injective f' := not_injective_infinite_finite f'
  contrapose! this
  intros n m hnm
  rw [Subtype.mk_eq_mk, add_right_inj, ← sub_eq_zero, ← sub_smul, smul_eq_zero, sub_eq_zero,
    sub_eq_zero] at hnm
  

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 • α
hβ : sβ α = α - 2 • β
hb : BijOn (⇑sαβ) (range ⇑P.root) (range ⇑P.root)
f : ℕ → M := fun n => β + (2 * ↑n) • (α - β)
hf : ∀ (n : ℕ), (⇑sαβ)^[n] β = f n
f' : ℕ → ↑(range ⇑P.root) := fun n => { val := f n, property := (_ : f n ∈ range ⇑P.root) }
this : i ≠ j
n m : ℕ
hnm : 2 * ↑n = 2 * ↑m ∨ α = β
⊢ n = m

Next tactic:
linarith [hnm.resolve_right (P.root.injective.ne this)]
lemma injOn_dualMap_subtype_span_root_coroot [NoZeroSMulDivisors ℤ M] :
    InjOn ((span R (range P.root)).subtype.dualMap ∘ₗ P.toLin.flip) (range P.coroot) := 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
⊢ InjOn (⇑(LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin)) (range ⇑P.coroot)

Next tactic:
rintro - ⟨i, rfl⟩ - ⟨j, rfl⟩ hij
lemma injOn_dualMap_subtype_span_root_coroot [NoZeroSMulDivisors ℤ M] :
    InjOn ((span R (range P.root)).subtype.dualMap ∘ₗ P.toLin.flip) (range P.coroot) := by
  rintro - ⟨i, rfl⟩ - ⟨j, rfl⟩ hij
  

Proof state:
case intro.intro
ι : 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 : ι
hij :
  (LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin) (P.coroot i) =
    (LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin) (P.coroot j)
⊢ P.coroot i = P.coroot j

Next tactic:
congr
lemma injOn_dualMap_subtype_span_root_coroot [NoZeroSMulDivisors ℤ M] :
    InjOn ((span R (range P.root)).subtype.dualMap ∘ₗ P.toLin.flip) (range P.coroot) := by
  rintro - ⟨i, rfl⟩ - ⟨j, rfl⟩ hij
  congr
  

Proof state:
case intro.intro.h.e_6.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✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
hij :
  (LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin) (P.coroot i) =
    (LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin) (P.coroot j)
⊢ i = j

Next tactic:
refine P.eq_of_forall_coroot_root_eq i j fun k ↦ ?_
lemma injOn_dualMap_subtype_span_root_coroot [NoZeroSMulDivisors ℤ M] :
    InjOn ((span R (range P.root)).subtype.dualMap ∘ₗ P.toLin.flip) (range P.coroot) := by
  rintro - ⟨i, rfl⟩ - ⟨j, rfl⟩ hij
  congr
  refine P.eq_of_forall_coroot_root_eq i j fun k ↦ ?_
  

Proof state:
case intro.intro.h.e_6.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✝ : ι
inst✝ : NoZeroSMulDivisors ℤ M
i j : ι
hij :
  (LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin) (P.coroot i) =
    (LinearMap.dualMap (Submodule.subtype (span R (range ⇑P.root))) ∘ₗ LinearMap.flip P.toLin) (P.coroot j)
k : ι
⊢ (P.toLin (P.root k)) (P.coroot i) = (P.toLin (P.root k)) (P.coroot j)

Next tactic:
simpa using LinearMap.congr_fun hij ⟨P.root k, Submodule.subset_span (mem_range_self k)⟩
/-- In characteristic zero if there is no torsion, the correspondence between roots and coroots is
unique.

Formally, the point is that the hypothesis `hc` depends only on the range of the coroot mappings. -/
@[ext]
protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
    {P₁ P₂ : RootPairing ι R M N}
    (he : P₁.toLin = P₂.toLin)
    (hr : P₁.root = P₂.root)
    (hc : range P₁.coroot = range P₂.coroot) :
    P₁ = P₂ := 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
inst✝ : NoZeroSMulDivisors R M
P₁ P₂ : RootPairing ι R M N
he : P₁.toLin = P₂.toLin
hr : P₁.root = P₂.root
hc : range ⇑P₁.coroot = range ⇑P₂.coroot
⊢ P₁ = P₂

Next tactic:
suffices P₁.coroot = P₂.coroot by cases' P₁ with p₁; cases' P₂ with p₂; cases p₁; cases p₂; congr
/-- In characteristic zero if there is no torsion, the correspondence between roots and coroots is
unique.

Formally, the point is that the hypothesis `hc` depends only on the range of the coroot mappings. -/
@[ext]
protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
    {P₁ P₂ : RootPairing ι R M N}
    (he : P₁.toLin = P₂.toLin)
    (hr : P₁.root = P₂.root)
    (hc : range P₁.coroot = range P₂.coroot) :
    P₁ = P₂ := by
  suffices P₁.coroot = P₂.coroot 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
inst✝ : NoZeroSMulDivisors R M
P₁ P₂ : RootPairing ι R M N
he : P₁.toLin = P₂.toLin
hr : P₁.root = P₂.root
hc : range ⇑P₁.coroot = range ⇑P₂.coroot
this : P₁.coroot = P₂.coroot
⊢ P₁ = P₂

Next tactic:
cases' P₁ with p₁
/-- In characteristic zero if there is no torsion, the correspondence between roots and coroots is
unique.

Formally, the point is that the hypothesis `hc` depends only on the range of the coroot mappings. -/
@[ext]
protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
    {P₁ P₂ : RootPairing ι R M N}
    (he : P₁.toLin = P₂.toLin)
    (hr : P₁.root = P₂.root)
    (hc : range P₁.coroot = range P₂.coroot) :
    P₁ = P₂ := by
  suffices P₁.coroot = P₂.coroot by cases' P₁ with p₁; 

Proof state:
case mk
ι : 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
inst✝ : NoZeroSMulDivisors R M
P₂ : RootPairing ι R M N
p₁ : PerfectPairing R M N
root✝ : ι ↪ M
coroot✝ : ι ↪ N
root_coroot_two✝ : ∀ (i : ι), (p₁.toLin (root✝ i)) (coroot✝ i) = 2
mapsTo_preReflection_root✝ :
  ∀ (i : ι), MapsTo (⇑(preReflection (root✝ i) ((LinearMap.flip p₁.toLin) (coroot✝ i)))) (range ⇑root✝) (range ⇑root✝)
mapsTo_preReflection_coroot✝ :
  ∀ (i : ι), MapsTo (⇑(preReflection (coroot✝ i) (p₁.toLin (root✝ i)))) (range ⇑coroot✝) (range ⇑coroot✝)
he :
  { toPerfectPairing := p₁, root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
          mapsTo_preReflection_root := mapsTo_preReflection_root✝,
          mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.toPerfectPairing.toLin =
    P₂.toLin
hr :
  { toPerfectPairing := p₁, root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
        mapsTo_preReflection_root := mapsTo_preReflection_root✝,
        mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.root =
    P₂.root
hc :
  range
      ⇑{ toPerfectPairing := p₁, root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
            mapsTo_preReflection_root := mapsTo_preReflection_root✝,
            mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.coroot =
    range ⇑P₂.coroot
this :
  { toPerfectPairing := p₁, root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
        mapsTo_preReflection_root := mapsTo_preReflection_root✝,
        mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.coroot =
    P₂.coroot
⊢ { toPerfectPairing := p₁, root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
      mapsTo_preReflection_root := mapsTo_preReflection_root✝,
      mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ } =
    P₂

Next tactic:
cases' P₂ with p₂
/-- In characteristic zero if there is no torsion, the correspondence between roots and coroots is
unique.

Formally, the point is that the hypothesis `hc` depends only on the range of the coroot mappings. -/
@[ext]
protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
    {P₁ P₂ : RootPairing ι R M N}
    (he : P₁.toLin = P₂.toLin)
    (hr : P₁.root = P₂.root)
    (hc : range P₁.coroot = range P₂.coroot) :
    P₁ = P₂ := by
  suffices P₁.coroot = P₂.coroot by cases' P₁ with p₁; cases' P₂ with p₂; cases p₁; cases p₂; congr
  

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
inst✝ : NoZeroSMulDivisors R M
P₁ P₂ : RootPairing ι R M N
he : P₁.toLin = P₂.toLin
hr : P₁.root = P₂.root
hc : range ⇑P₁.coroot = range ⇑P₂.coroot
⊢ P₁.coroot = P₂.coroot

Next tactic:
have := NoZeroSMulDivisors.int_of_charZero R M
/-- In characteristic zero if there is no torsion, the correspondence between roots and coroots is
unique.

Formally, the point is that the hypothesis `hc` depends only on the range of the coroot mappings. -/
@[ext]
protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
    {P₁ P₂ : RootPairing ι R M N}
    (he : P₁.toLin = P₂.toLin)
    (hr : P₁.root = P₂.root)
    (hc : range P₁.coroot = range P₂.coroot) :
    P₁ = P₂ := by
  suffices P₁.coroot = P₂.coroot by cases' P₁ with p₁; cases' P₂ with p₂; cases p₁; cases p₂; congr
  have := NoZeroSMulDivisors.int_of_charZero R M
  

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
inst✝ : NoZeroSMulDivisors R M
P₁ P₂ : RootPairing ι R M N
he : P₁.toLin = P₂.toLin
hr : P₁.root = P₂.root
hc : range ⇑P₁.coroot = range ⇑P₂.coroot
this : NoZeroSMulDivisors ℤ M
⊢ P₁.coroot = P₂.coroot

Next tactic:
ext i
/-- In characteristic zero if there is no torsion, the correspondence between roots and coroots is
unique.

Formally, the point is that the hypothesis `hc` depends only on the range of the coroot mappings. -/
@[ext]
protected lemma ext [CharZero R] [NoZeroSMulDivisors R M]
    {P₁ P₂ : RootPairing ι R M N}
    (he : P₁.toLin = P₂.toLin)
    (hr : P₁.root = P₂.root)
    (hc : range P₁.coroot = range P₂.coroot) :
    P₁ = P₂ := by
  suffices P₁.coroot = P₂.coroot by cases' P₁ with p₁; cases' P₂ with p₂; cases p₁; cases p₂; congr
  have := NoZeroSMulDivisors.int_of_charZero R M
  ext i
  

Proof state:
case 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✝ : ι
inst✝¹ : CharZero R
inst✝ : NoZeroSMulDivisors R M
P₁ P₂ : RootPairing ι R M N
he : P₁.toLin = P₂.toLin
hr : P₁.root = P₂.root
hc : range ⇑P₁.coroot = range ⇑P₂.coroot
this : NoZeroSMulDivisors ℤ M
i : ι
⊢ P₁.coroot i = P₂.coroot i

Next tactic:
apply P₁.injOn_dualMap_subtype_span_root_coroot (mem_range_self i) (hc ▸ mem_range_self i)