l3lab/ntp-mathlib huggingface dataset:
theorem Algebra.homEquiv_naturality_str (adj : F ⊣ G) (A₁ A₂ : Algebra F) (f : A₁ ⟶ A₂) :
    (adj.homEquiv A₁.a A₁.a) A₁.str ≫ G.map f.f = f.f ≫ (adj.homEquiv A₂.a A₂.a) A₂.str := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A₁ A₂ : Algebra F
f : A₁ ⟶ A₂
⊢ (Adjunction.homEquiv adj A₁.a A₁.a) A₁.str ≫ G.map f.f = f.f ≫ (Adjunction.homEquiv adj A₂.a A₂.a) A₂.str

Next tactic:
rw [← Adjunction.homEquiv_naturality_right, ← Adjunction.homEquiv_naturality_left, f.h]
theorem Coalgebra.homEquiv_naturality_str_symm (adj : F ⊣ G) (V₁ V₂ : Coalgebra G) (f : V₁ ⟶ V₂) :
    F.map f.f ≫ (adj.homEquiv V₂.V V₂.V).symm V₂.str =
    (adj.homEquiv V₁.V V₁.V).symm V₁.str ≫ f.f := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V₁ V₂ : Coalgebra G
f : V₁ ⟶ V₂
⊢ F.map f.f ≫ (Adjunction.homEquiv adj V₂.V V₂.V).symm V₂.str = (Adjunction.homEquiv adj V₁.V V₁.V).symm V₁.str ≫ f.f

Next tactic:
rw [← Adjunction.homEquiv_naturality_left_symm, ← Adjunction.homEquiv_naturality_right_symm,
    f.h]
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A : Algebra F
⊢ F.map (𝟙 A.a) ≫ ((Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj).obj A).str =
    ((𝟭 (Algebra F)).obj A).str ≫ 𝟙 A.a

Next tactic:
erw [F.map_id, Category.id_comp, Category.comp_id]
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A : Algebra F
⊢ ((Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj).obj A).str = ((𝟭 (Algebra F)).obj A).str

Next tactic:
apply (adj.homEquiv _ _).left_inv A.str
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).left_inv A.str } }
  inv :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A : Algebra F
⊢ F.map (𝟙 A.a) ≫ ((𝟭 (Algebra F)).obj A).str =
    ((Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj).obj A).str ≫ 𝟙 A.a

Next tactic:
erw [F.map_id, Category.id_comp, Category.comp_id]
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).left_inv A.str } }
  inv :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A : Algebra F
⊢ ((𝟭 (Algebra F)).obj A).str = ((Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj).obj A).str

Next tactic:
apply ((adj.homEquiv _ _).left_inv A.str).symm
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).left_inv A.str } }
  inv :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply ((adj.homEquiv _ _).left_inv A.str).symm }
      naturality := fun A₁ A₂ f => by
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A₁ A₂ : Algebra F
f : A₁ ⟶ A₂
⊢ (Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj).map f ≫ (fun A => Algebra.Hom.mk (𝟙 A.a)) A₂ =
    (fun A => Algebra.Hom.mk (𝟙 A.a)) A₁ ≫ (𝟭 (Algebra F)).map f

Next tactic:
ext
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).left_inv A.str } }
  inv :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply ((adj.homEquiv _ _).left_inv A.str).symm }
      naturality := fun A₁ A₂ f => by
        ext
        

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A₁ A₂ : Algebra F
f : A₁ ⟶ A₂
⊢ autoParam
    (((Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj).map f ≫ (fun A => Algebra.Hom.mk (𝟙 A.a)) A₂).f =
      ((fun A => Algebra.Hom.mk (𝟙 A.a)) A₁ ≫ (𝟭 (Algebra F)).map f).f)
    _auto✝

Next tactic:
dsimp
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).left_inv A.str } }
  inv :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply ((adj.homEquiv _ _).left_inv A.str).symm }
      naturality := fun A₁ A₂ f => by
        ext
        dsimp
        

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A₁ A₂ : Algebra F
f : A₁ ⟶ A₂
⊢ autoParam (((Coalgebra.toAlgebraOf adj).map ((Algebra.toCoalgebraOf adj).map f)).f ≫ 𝟙 A₂.a = 𝟙 A₁.a ≫ f.f) _auto✝

Next tactic:
erw [Category.comp_id, Category.id_comp]
/-- Given an adjunction, assigning to an algebra over the left adjoint a coalgebra over its right
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.unitIso (adj : F ⊣ G) :
    𝟭 (Algebra F) ≅ Algebra.toCoalgebraOf adj ⋙ Coalgebra.toAlgebraOf adj where
  hom :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).left_inv A.str } }
  inv :=
    { app := fun A =>
        { f := 𝟙 A.1
          h := by
            erw [F.map_id, Category.id_comp, Category.comp_id]
            apply ((adj.homEquiv _ _).left_inv A.str).symm }
      naturality := fun A₁ A₂ f => by
        ext
        dsimp
        erw [Category.comp_id, Category.id_comp]
        

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A₁ A₂ : Algebra F
f : A₁ ⟶ A₂
⊢ autoParam (((Coalgebra.toAlgebraOf adj).map ((Algebra.toCoalgebraOf adj).map f)).f = f.f) _auto✝

Next tactic:
rfl
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V : Coalgebra G
⊢ ((Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj).obj V).str ≫ G.map (𝟙 V.V) =
    𝟙 V.V ≫ ((𝟭 (Coalgebra G)).obj V).str

Next tactic:
dsimp
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V : Coalgebra G
⊢ ((Algebra.toCoalgebraOf adj).obj ((Coalgebra.toAlgebraOf adj).obj V)).str ≫ G.map (𝟙 V.V) = 𝟙 V.V ≫ V.str

Next tactic:
erw [G.map_id, Category.id_comp, Category.comp_id]
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V : Coalgebra G
⊢ ((Algebra.toCoalgebraOf adj).obj ((Coalgebra.toAlgebraOf adj).obj V)).str = V.str

Next tactic:
apply (adj.homEquiv _ _).right_inv V.str
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V₁ V₂ : Coalgebra G
f : V₁ ⟶ V₂
⊢ (Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj).map f ≫ (fun V => Coalgebra.Hom.mk (𝟙 V.V)) V₂ =
    (fun V => Coalgebra.Hom.mk (𝟙 V.V)) V₁ ≫ (𝟭 (Coalgebra G)).map f

Next tactic:
ext
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        ext
        

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V₁ V₂ : Coalgebra G
f : V₁ ⟶ V₂
⊢ autoParam
    (((Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj).map f ≫ (fun V => Coalgebra.Hom.mk (𝟙 V.V)) V₂).f =
      ((fun V => Coalgebra.Hom.mk (𝟙 V.V)) V₁ ≫ (𝟭 (Coalgebra G)).map f).f)
    _auto✝

Next tactic:
dsimp
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        ext
        dsimp
        

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V₁ V₂ : Coalgebra G
f : V₁ ⟶ V₂
⊢ autoParam (((Algebra.toCoalgebraOf adj).map ((Coalgebra.toAlgebraOf adj).map f)).f ≫ 𝟙 V₂.V = 𝟙 V₁.V ≫ f.f) _auto✝

Next tactic:
erw [Category.comp_id, Category.id_comp]
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        ext
        dsimp
        erw [Category.comp_id, Category.id_comp]
        

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V₁ V₂ : Coalgebra G
f : V₁ ⟶ V₂
⊢ autoParam (((Algebra.toCoalgebraOf adj).map ((Coalgebra.toAlgebraOf adj).map f)).f = f.f) _auto✝

Next tactic:
rfl
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        ext
        dsimp
        erw [Category.comp_id, Category.id_comp]
        rfl }
  inv :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V : Coalgebra G
⊢ ((𝟭 (Coalgebra G)).obj V).str ≫ G.map (𝟙 V.V) =
    𝟙 V.V ≫ ((Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj).obj V).str

Next tactic:
dsimp
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        ext
        dsimp
        erw [Category.comp_id, Category.id_comp]
        rfl }
  inv :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V : Coalgebra G
⊢ V.str ≫ G.map (𝟙 V.V) = 𝟙 V.V ≫ ((Algebra.toCoalgebraOf adj).obj ((Coalgebra.toAlgebraOf adj).obj V)).str

Next tactic:
rw [G.map_id, Category.comp_id, Category.id_comp]
/-- Given an adjunction, assigning to a coalgebra over the right adjoint an algebra over the left
adjoint and going back is isomorphic to the identity functor. -/
def AlgCoalgEquiv.counitIso (adj : F ⊣ G) :
    Coalgebra.toAlgebraOf adj ⋙ Algebra.toCoalgebraOf adj ≅ 𝟭 (Coalgebra G) where
  hom :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            erw [G.map_id, Category.id_comp, Category.comp_id]
            apply (adj.homEquiv _ _).right_inv V.str }
      naturality := fun V₁ V₂ f => by
        ext
        dsimp
        erw [Category.comp_id, Category.id_comp]
        rfl }
  inv :=
    { app := fun V =>
        { f := 𝟙 V.1
          h := by
            dsimp
            rw [G.map_id, Category.comp_id, Category.id_comp]
            

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
V : Coalgebra G
⊢ V.str = ((Algebra.toCoalgebraOf adj).obj ((Coalgebra.toAlgebraOf adj).obj V)).str

Next tactic:
apply ((adj.homEquiv _ _).right_inv V.str).symm
/-- If `F` is left adjoint to `G`, then the category of algebras over `F` is equivalent to the
category of coalgebras over `G`. -/
def algebraCoalgebraEquiv (adj : F ⊣ G) : Algebra F ≌ Coalgebra G where
  functor := Algebra.toCoalgebraOf adj
  inverse := Coalgebra.toAlgebraOf adj
  unitIso := AlgCoalgEquiv.unitIso adj
  counitIso := AlgCoalgEquiv.counitIso adj
  functor_unitIso_comp A := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A : Algebra F
⊢ (Algebra.toCoalgebraOf adj).map ((AlgCoalgEquiv.unitIso adj).hom.app A) ≫
      (AlgCoalgEquiv.counitIso adj).hom.app ((Algebra.toCoalgebraOf adj).obj A) =
    𝟙 ((Algebra.toCoalgebraOf adj).obj A)

Next tactic:
ext
/-- If `F` is left adjoint to `G`, then the category of algebras over `F` is equivalent to the
category of coalgebras over `G`. -/
def algebraCoalgebraEquiv (adj : F ⊣ G) : Algebra F ≌ Coalgebra G where
  functor := Algebra.toCoalgebraOf adj
  inverse := Coalgebra.toAlgebraOf adj
  unitIso := AlgCoalgEquiv.unitIso adj
  counitIso := AlgCoalgEquiv.counitIso adj
  functor_unitIso_comp A := by
    ext
    -- Porting note: why doesn't `simp` work here?
    

Proof state:
case w
C : Type u
inst✝ : Category.{v, u} C
F G : C ⥤ C
adj : F ⊣ G
A : Algebra F
⊢ autoParam
    (((Algebra.toCoalgebraOf adj).map ((AlgCoalgEquiv.unitIso adj).hom.app A) ≫
          (AlgCoalgEquiv.counitIso adj).hom.app ((Algebra.toCoalgebraOf adj).obj A)).f =
      (𝟙 ((Algebra.toCoalgebraOf adj).obj A)).f)
    _auto✝

Next tactic:
exact Category.comp_id _
@[to_additive]
noncomputable instance [CommMonoid M] : CommGroup (IsUnit.submonoid M) :=
  { inferInstanceAs (Group (IsUnit.submonoid M)) with
    mul_comm := fun a b ↦ by 

Proof state:
M : Type u_1
inst✝ : CommMonoid M
src✝ : Group ↥(IsUnit.submonoid M) := inferInstanceAs (Group ↥(IsUnit.submonoid M))
a b : ↥(IsUnit.submonoid M)
⊢ a * b = b * a

Next tactic:
convert mul_comm a b
/-- `S.leftInv` is the submonoid containing all the left inverses of `S`. -/
@[to_additive
      "`S.leftNeg` is the additive submonoid containing all the left additive inverses of `S`."]
def leftInv : Submonoid M where
  carrier := { x : M | ∃ y : S, x * y = 1 }
  one_mem' := ⟨1, mul_one 1⟩
  mul_mem' := fun {a} _b ⟨a', ha⟩ ⟨b', hb⟩ ↦
    ⟨b' * a', by 

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
a _b : M
x✝¹ : a ∈ {x | ∃ y, x * ↑y = 1}
x✝ : _b ∈ {x | ∃ y, x * ↑y = 1}
a' : ↥S
ha : a * ↑a' = 1
b' : ↥S
hb : _b * ↑b' = 1
⊢ a * _b * ↑(b' * a') = 1

Next tactic:
simp only [coe_mul, ← mul_assoc, mul_assoc a, hb, mul_one, ha]
@[to_additive]
theorem leftInv_leftInv_le : S.leftInv.leftInv ≤ S := by
  

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
⊢ leftInv (leftInv S) ≤ S

Next tactic:
rintro x ⟨⟨y, z, h₁⟩, h₂ : x * y = 1⟩
@[to_additive]
theorem leftInv_leftInv_le : S.leftInv.leftInv ≤ S := by
  rintro x ⟨⟨y, z, h₁⟩, h₂ : x * y = 1⟩
  

Proof state:
case intro.mk.intro
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
x y : M
z : ↥S
h₁ : y * ↑z = 1
h₂ : x * y = 1
⊢ x ∈ S

Next tactic:
convert z.prop
@[to_additive]
theorem leftInv_leftInv_le : S.leftInv.leftInv ≤ S := by
  rintro x ⟨⟨y, z, h₁⟩, h₂ : x * y = 1⟩
  convert z.prop
  

Proof state:
case h.e'_4
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
x y : M
z : ↥S
h₁ : y * ↑z = 1
h₂ : x * y = 1
⊢ x = ↑z

Next tactic:
rw [← mul_one x, ← h₁, ← mul_assoc, h₂, one_mul]
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
⊢ leftInv (leftInv S) = S

Next tactic:
refine' le_antisymm S.leftInv_leftInv_le _
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  refine' le_antisymm S.leftInv_leftInv_le _
  

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
⊢ S ≤ leftInv (leftInv S)

Next tactic:
intro x hx
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  refine' le_antisymm S.leftInv_leftInv_le _
  intro x hx
  

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
x : M
hx : x ∈ S
⊢ x ∈ leftInv (leftInv S)

Next tactic:
have : x = ((hS hx).unit⁻¹⁻¹ : Mˣ) := by
    rw [inv_inv (hS hx).unit]
    rfl
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  refine' le_antisymm S.leftInv_leftInv_le _
  intro x hx
  have : x = ((hS hx).unit⁻¹⁻¹ : Mˣ) := by
    

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
x : M
hx : x ∈ S
⊢ x = ↑(IsUnit.unit (_ : x ∈ IsUnit.submonoid M))⁻¹⁻¹

Next tactic:
rw [inv_inv (hS hx).unit]
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  refine' le_antisymm S.leftInv_leftInv_le _
  intro x hx
  have : x = ((hS hx).unit⁻¹⁻¹ : Mˣ) := by
    rw [inv_inv (hS hx).unit]
    

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
x : M
hx : x ∈ S
⊢ x = ↑(IsUnit.unit (_ : x ∈ IsUnit.submonoid M))

Next tactic:
rfl
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  refine' le_antisymm S.leftInv_leftInv_le _
  intro x hx
  have : x = ((hS hx).unit⁻¹⁻¹ : Mˣ) := by
    rw [inv_inv (hS hx).unit]
    rfl
  

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
x : M
hx : x ∈ S
this : x = ↑(IsUnit.unit (_ : x ∈ IsUnit.submonoid M))⁻¹⁻¹
⊢ x ∈ leftInv (leftInv S)

Next tactic:
rw [this]
@[to_additive]
theorem leftInv_leftInv_eq (hS : S ≤ IsUnit.submonoid M) : S.leftInv.leftInv = S := by
  refine' le_antisymm S.leftInv_leftInv_le _
  intro x hx
  have : x = ((hS hx).unit⁻¹⁻¹ : Mˣ) := by
    rw [inv_inv (hS hx).unit]
    rfl
  rw [this]
  

Proof state:
M : Type u_1
inst✝ : Monoid M
S : Submonoid M
hS : S ≤ IsUnit.submonoid M
x : M
hx : x ∈ S
this : x = ↑(IsUnit.unit (_ : x ∈ IsUnit.submonoid M))⁻¹⁻¹
⊢ ↑(IsUnit.unit (_ : x ∈ IsUnit.submonoid M))⁻¹⁻¹ ∈ leftInv (leftInv S)

Next tactic:
exact S.leftInv.unit_mem_leftInv _ (S.unit_mem_leftInv _ hx)
@[to_additive (attr := simp)]
theorem fromLeftInv_mul (x : S.leftInv) : (S.fromLeftInv x : M) * x = 1 := by
  

Proof state:
M : Type u_1
inst✝ : CommMonoid M
S : Submonoid M
x : ↥(leftInv S)
⊢ ↑(fromLeftInv S x) * ↑x = 1

Next tactic:
rw [mul_comm, mul_fromLeftInv]
@[to_additive]
theorem fromLeftInv_eq_iff (a : S.leftInv) (b : M) : (S.fromLeftInv a : M) = b ↔ (a : M) * b = 1 :=
  by 

Proof state:
M : Type u_1
inst✝ : CommMonoid M
S : Submonoid M
a : ↥(leftInv S)
b : M
⊢ ↑(fromLeftInv S a) = b ↔ ↑a * b = 1

Next tactic:
rw [← IsUnit.mul_right_inj (leftInv_le_isUnit _ a.prop), S.mul_fromLeftInv, eq_comm]
/-- The `MonoidHom` from `S.leftInv` to `S` sending an element to its right inverse in `S`. -/
@[to_additive (attr := simps)
    "The `AddMonoidHom` from `S.leftNeg` to `S` sending an element to its
    right additive inverse in `S`."]
noncomputable def fromCommLeftInv : S.leftInv →* S where
  toFun := S.fromLeftInv
  map_one' := S.fromLeftInv_one
  map_mul' x y :=
    Subtype.ext <| by
      

Proof state:
M : Type u_1
inst✝ : CommMonoid M
S : Submonoid M
x y : ↥(leftInv S)
⊢ ↑(OneHom.toFun { toFun := fromLeftInv S, map_one' := (_ : fromLeftInv S 1 = 1) } (x * y)) =
    ↑(OneHom.toFun { toFun := fromLeftInv S, map_one' := (_ : fromLeftInv S 1 = 1) } x *
        OneHom.toFun { toFun := fromLeftInv S, map_one' := (_ : fromLeftInv S 1 = 1) } y)

Next tactic:
rw [fromLeftInv_eq_iff, mul_comm x, Submonoid.coe_mul, Submonoid.coe_mul, mul_assoc, ←
        mul_assoc (x : M), mul_fromLeftInv, one_mul, mul_fromLeftInv]