/-- 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
    · 

Proof state:
case mk.mk.mk.mk.mk.mk.mk.mk.mk.mk.h2
R : Type u_1
inst✝ : CommRing R
xr xrε xi xiε xj xjε xk xkε yr yrε yi yiε yj yjε yk ykε : R
⊢ TrivSqZeroExt.snd
      (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ε) })) =
    TrivSqZeroExt.snd
      (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:
dsimp