/-- 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₂; 

Proof state:
case mk.mk.mk.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
root✝¹ : ι ↪ M
coroot✝¹ : ι ↪ N
root✝ : ι ↪ M
coroot✝ : ι ↪ N
toLin✝¹ : M →ₗ[R] N →ₗ[R] R
bijectiveLeft✝¹ : Bijective ⇑toLin✝¹
bijectiveRight✝¹ : Bijective ⇑(LinearMap.flip toLin✝¹)
root_coroot_two✝¹ :
  ∀ (i : ι),
    ({ toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ }.toLin (root✝¹ i))
        (coroot✝¹ i) =
      2
mapsTo_preReflection_root✝¹ :
  ∀ (i : ι),
    MapsTo
      (⇑(preReflection (root✝¹ i)
          ((LinearMap.flip
              { toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ }.toLin)
            (coroot✝¹ i))))
      (range ⇑root✝¹) (range ⇑root✝¹)
mapsTo_preReflection_coroot✝¹ :
  ∀ (i : ι),
    MapsTo
      (⇑(preReflection (coroot✝¹ i)
          ({ toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ }.toLin
            (root✝¹ i))))
      (range ⇑coroot✝¹) (range ⇑coroot✝¹)
toLin✝ : M →ₗ[R] N →ₗ[R] R
bijectiveLeft✝ : Bijective ⇑toLin✝
bijectiveRight✝ : Bijective ⇑(LinearMap.flip toLin✝)
root_coroot_two✝ :
  ∀ (i : ι),
    ({ toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ }.toLin (root✝ i))
        (coroot✝ i) =
      2
mapsTo_preReflection_root✝ :
  ∀ (i : ι),
    MapsTo
      (⇑(preReflection (root✝ i)
          ((LinearMap.flip
              { toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ }.toLin)
            (coroot✝ i))))
      (range ⇑root✝) (range ⇑root✝)
mapsTo_preReflection_coroot✝ :
  ∀ (i : ι),
    MapsTo
      (⇑(preReflection (coroot✝ i)
          ({ toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ }.toLin (root✝ i))))
      (range ⇑coroot✝) (range ⇑coroot✝)
he :
  { toPerfectPairing := { toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ },
          root := root✝¹, coroot := coroot✝¹, root_coroot_two := root_coroot_two✝¹,
          mapsTo_preReflection_root := mapsTo_preReflection_root✝¹,
          mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝¹ }.toPerfectPairing.toLin =
    { toPerfectPairing := { toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ },
          root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
          mapsTo_preReflection_root := mapsTo_preReflection_root✝,
          mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.toPerfectPairing.toLin
hr :
  { toPerfectPairing := { toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ },
        root := root✝¹, coroot := coroot✝¹, root_coroot_two := root_coroot_two✝¹,
        mapsTo_preReflection_root := mapsTo_preReflection_root✝¹,
        mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝¹ }.root =
    { toPerfectPairing := { toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ },
        root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
        mapsTo_preReflection_root := mapsTo_preReflection_root✝,
        mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.root
hc :
  range
      ⇑{ toPerfectPairing := { toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ },
            root := root✝¹, coroot := coroot✝¹, root_coroot_two := root_coroot_two✝¹,
            mapsTo_preReflection_root := mapsTo_preReflection_root✝¹,
            mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝¹ }.coroot =
    range
      ⇑{ toPerfectPairing := { toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ },
            root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
            mapsTo_preReflection_root := mapsTo_preReflection_root✝,
            mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.coroot
this :
  { toPerfectPairing := { toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ },
        root := root✝¹, coroot := coroot✝¹, root_coroot_two := root_coroot_two✝¹,
        mapsTo_preReflection_root := mapsTo_preReflection_root✝¹,
        mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝¹ }.coroot =
    { toPerfectPairing := { toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ },
        root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
        mapsTo_preReflection_root := mapsTo_preReflection_root✝,
        mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }.coroot
⊢ { toPerfectPairing := { toLin := toLin✝¹, bijectiveLeft := bijectiveLeft✝¹, bijectiveRight := bijectiveRight✝¹ },
      root := root✝¹, coroot := coroot✝¹, root_coroot_two := root_coroot_two✝¹,
      mapsTo_preReflection_root := mapsTo_preReflection_root✝¹,
      mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝¹ } =
    { toPerfectPairing := { toLin := toLin✝, bijectiveLeft := bijectiveLeft✝, bijectiveRight := bijectiveRight✝ },
      root := root✝, coroot := coroot✝, root_coroot_two := root_coroot_two✝,
      mapsTo_preReflection_root := mapsTo_preReflection_root✝,
      mapsTo_preReflection_coroot := mapsTo_preReflection_coroot✝ }

Next tactic:
congr