/-- Units in the monoid of endomorphisms of an object
are (multiplicatively) equivalent to automorphisms of that object.
-/
def unitsEndEquivAut : (End X)ˣ ≃* Aut X where
  toFun f := ⟨f.1, f.2, f.4, f.3⟩
  invFun f := ⟨f.1, f.2, f.4, f.3⟩
  left_inv := fun ⟨f₁, f₂, f₃, f₄⟩ => rfl
  right_inv := fun ⟨f₁, f₂, f₃, f₄⟩ => rfl
  map_mul' f g := by cases f; 

Proof state:
case mk
C : Type u
inst✝ : Category.{v, u} C
X : C
g : (End X)ˣ
val✝ inv✝ : End X
val_inv✝ : val✝ * inv✝ = 1
inv_val✝ : inv✝ * val✝ = 1
⊢ Equiv.toFun
      { toFun := fun f => Iso.mk (↑f) f.inv,
        invFun := fun f =>
          { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X), inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) },
        left_inv :=
          (_ :
            ∀ (x : (End X)ˣ),
              (fun f =>
                    { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X),
                      inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) })
                  ((fun f => Iso.mk (↑f) f.inv) x) =
                x),
        right_inv :=
          (_ :
            ∀ (x : Aut X),
              (fun f => Iso.mk (↑f) f.inv)
                  ((fun f =>
                      { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X),
                        inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) })
                    x) =
                x) }
      ({ val := val✝, inv := inv✝, val_inv := val_inv✝, inv_val := inv_val✝ } * g) =
    Equiv.toFun
        { toFun := fun f => Iso.mk (↑f) f.inv,
          invFun := fun f =>
            { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X), inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) },
          left_inv :=
            (_ :
              ∀ (x : (End X)ˣ),
                (fun f =>
                      { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X),
                        inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) })
                    ((fun f => Iso.mk (↑f) f.inv) x) =
                  x),
          right_inv :=
            (_ :
              ∀ (x : Aut X),
                (fun f => Iso.mk (↑f) f.inv)
                    ((fun f =>
                        { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X),
                          inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) })
                      x) =
                  x) }
        { val := val✝, inv := inv✝, val_inv := val_inv✝, inv_val := inv_val✝ } *
      Equiv.toFun
        { toFun := fun f => Iso.mk (↑f) f.inv,
          invFun := fun f =>
            { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X), inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) },
          left_inv :=
            (_ :
              ∀ (x : (End X)ˣ),
                (fun f =>
                      { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X),
                        inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) })
                    ((fun f => Iso.mk (↑f) f.inv) x) =
                  x),
          right_inv :=
            (_ :
              ∀ (x : Aut X),
                (fun f => Iso.mk (↑f) f.inv)
                    ((fun f =>
                        { val := f.hom, inv := f.inv, val_inv := (_ : f.inv ≫ f.hom = 𝟙 X),
                          inv_val := (_ : f.hom ≫ f.inv = 𝟙 X) })
                      x) =
                  x) }
        g

Next tactic:
cases g