/-- The dual quaternions can be equivalently represented as a quaternion with dual coefficients,
or as a dual number with quaternion coefficients.

See also `Matrix.dualNumberEquiv` for a similar result. -/
def dualNumberEquiv : Quaternion (DualNumber R) ≃ₐ[R] DualNumber (Quaternion R) where
  toFun q :=
    (⟨q.re.fst, q.imI.fst, q.imJ.fst, q.imK.fst⟩, ⟨q.re.snd, q.imI.snd, q.imJ.snd, q.imK.snd⟩)
  invFun d :=
    ⟨(d.fst.re, d.snd.re), (d.fst.imI, d.snd.imI), (d.fst.imJ, d.snd.imJ), (d.fst.imK, d.snd.imK)⟩
  left_inv := fun ⟨⟨r, rε⟩, ⟨i, iε⟩, ⟨j, jε⟩, ⟨k, kε⟩⟩ => rfl
  right_inv := fun ⟨⟨r, i, j, k⟩, ⟨rε, iε, jε, kε⟩⟩ => rfl
  map_mul' := by
    rintro ⟨⟨xr, xrε⟩, ⟨xi, xiε⟩, ⟨xj, xjε⟩, ⟨xk, xkε⟩⟩
    rintro ⟨⟨yr, yrε⟩, ⟨yi, yiε⟩, ⟨yj, yjε⟩, ⟨yk, ykε⟩⟩
    ext : 1
    · rfl
    · dsimp
      congr 1 <;> simp <;> ring
  map_add' := by
    rintro ⟨⟨xr, xrε⟩, ⟨xi, xiε⟩, ⟨xj, xjε⟩, ⟨xk, xkε⟩⟩
    rintro ⟨⟨yr, yrε⟩, ⟨yi, yiε⟩, ⟨yj, yjε⟩, ⟨yk, ykε⟩⟩
    

Proof state:
case mk.mk.mk.mk.mk.mk.mk.mk.mk.mk
R : Type u_1
inst✝ : CommRing R
xr xrε xi xiε xj xjε xk xkε yr yrε yi yiε yj yjε yk ykε : R
⊢ Equiv.toFun
      {
        toFun := fun q =>
          ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
              imK := TrivSqZeroExt.fst q.imK },
            { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
              imK := TrivSqZeroExt.snd q.imK }),
        invFun := fun d =>
          { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
            imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
            imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
            imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) },
        left_inv :=
          (_ :
            ∀ (x : ℍ[DualNumber R]),
              (fun d =>
                    { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
                      imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
                      imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
                      imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) })
                  ((fun q =>
                      ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                          imK := TrivSqZeroExt.fst q.imK },
                        { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
                          imK := TrivSqZeroExt.snd q.imK }))
                    x) =
                x),
        right_inv :=
          (_ :
            ∀ (x : DualNumber ℍ[R]),
              (fun q =>
                    ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                        imK := TrivSqZeroExt.fst q.imK },
                      { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
                        imK := TrivSqZeroExt.snd q.imK }))
                  ((fun d =>
                      { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
                        imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
                        imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
                        imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) })
                    x) =
                x) }
      ({ re := (xr, xrε), imI := (xi, xiε), imJ := (xj, xjε), imK := (xk, xkε) } +
        { re := (yr, yrε), imI := (yi, yiε), imJ := (yj, yjε), imK := (yk, ykε) }) =
    Equiv.toFun
        {
          toFun := fun q =>
            ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                imK := TrivSqZeroExt.fst q.imK },
              { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
                imK := TrivSqZeroExt.snd q.imK }),
          invFun := fun d =>
            { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
              imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
              imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
              imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) },
          left_inv :=
            (_ :
              ∀ (x : ℍ[DualNumber R]),
                (fun d =>
                      { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
                        imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
                        imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
                        imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) })
                    ((fun q =>
                        ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                            imK := TrivSqZeroExt.fst q.imK },
                          { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI,
                            imJ := TrivSqZeroExt.snd q.imJ, imK := TrivSqZeroExt.snd q.imK }))
                      x) =
                  x),
          right_inv :=
            (_ :
              ∀ (x : DualNumber ℍ[R]),
                (fun q =>
                      ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                          imK := TrivSqZeroExt.fst q.imK },
                        { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
                          imK := TrivSqZeroExt.snd q.imK }))
                    ((fun d =>
                        { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
                          imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
                          imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
                          imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) })
                      x) =
                  x) }
        { re := (xr, xrε), imI := (xi, xiε), imJ := (xj, xjε), imK := (xk, xkε) } +
      Equiv.toFun
        {
          toFun := fun q =>
            ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                imK := TrivSqZeroExt.fst q.imK },
              { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
                imK := TrivSqZeroExt.snd q.imK }),
          invFun := fun d =>
            { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
              imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
              imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
              imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) },
          left_inv :=
            (_ :
              ∀ (x : ℍ[DualNumber R]),
                (fun d =>
                      { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
                        imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
                        imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
                        imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) })
                    ((fun q =>
                        ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                            imK := TrivSqZeroExt.fst q.imK },
                          { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI,
                            imJ := TrivSqZeroExt.snd q.imJ, imK := TrivSqZeroExt.snd q.imK }))
                      x) =
                  x),
          right_inv :=
            (_ :
              ∀ (x : DualNumber ℍ[R]),
                (fun q =>
                      ({ re := TrivSqZeroExt.fst q.re, imI := TrivSqZeroExt.fst q.imI, imJ := TrivSqZeroExt.fst q.imJ,
                          imK := TrivSqZeroExt.fst q.imK },
                        { re := TrivSqZeroExt.snd q.re, imI := TrivSqZeroExt.snd q.imI, imJ := TrivSqZeroExt.snd q.imJ,
                          imK := TrivSqZeroExt.snd q.imK }))
                    ((fun d =>
                        { re := ((TrivSqZeroExt.fst d).re, (TrivSqZeroExt.snd d).re),
                          imI := ((TrivSqZeroExt.fst d).imI, (TrivSqZeroExt.snd d).imI),
                          imJ := ((TrivSqZeroExt.fst d).imJ, (TrivSqZeroExt.snd d).imJ),
                          imK := ((TrivSqZeroExt.fst d).imK, (TrivSqZeroExt.snd d).imK) })
                      x) =
                  x) }
        { re := (yr, yrε), imI := (yi, yiε), imJ := (yj, yjε), imK := (yk, ykε) }

Next tactic:
rfl