l3lab/ntp-mathlib huggingface dataset:
/-- `(M →* N)` is a `CommMonoid` if `N` is commutative. -/
@[to_additive "`(M →+ N)` is an `AddCommMonoid` if `N` is commutative."]
instance MonoidHom.commMonoid [MulOneClass M] [CommMonoid N] :
    CommMonoid (M →* N) where
  mul := (· * ·)
  mul_assoc := by intros; ext; apply mul_assoc
  one := 1
  one_mul := by intros; ext; apply one_mul
  mul_one := by intros; ext; apply mul_one
  mul_comm := by 

Proof state:
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝¹ : MulOneClass M
inst✝ : CommMonoid N
⊢ ∀ (a b : M →* N), a * b = b * a

Next tactic:
intros
/-- `(M →* N)` is a `CommMonoid` if `N` is commutative. -/
@[to_additive "`(M →+ N)` is an `AddCommMonoid` if `N` is commutative."]
instance MonoidHom.commMonoid [MulOneClass M] [CommMonoid N] :
    CommMonoid (M →* N) where
  mul := (· * ·)
  mul_assoc := by intros; ext; apply mul_assoc
  one := 1
  one_mul := by intros; ext; apply one_mul
  mul_one := by intros; ext; apply mul_one
  mul_comm := by intros; 

Proof state:
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝¹ : MulOneClass M
inst✝ : CommMonoid N
a✝ b✝ : M →* N
⊢ a✝ * b✝ = b✝ * a✝

Next tactic:
ext
/-- `(M →* N)` is a `CommMonoid` if `N` is commutative. -/
@[to_additive "`(M →+ N)` is an `AddCommMonoid` if `N` is commutative."]
instance MonoidHom.commMonoid [MulOneClass M] [CommMonoid N] :
    CommMonoid (M →* N) where
  mul := (· * ·)
  mul_assoc := by intros; ext; apply mul_assoc
  one := 1
  one_mul := by intros; ext; apply one_mul
  mul_one := by intros; ext; apply mul_one
  mul_comm := by intros; ext; 

Proof state:
case h
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝¹ : MulOneClass M
inst✝ : CommMonoid N
a✝ b✝ : M →* N
x✝ : M
⊢ (a✝ * b✝) x✝ = (b✝ * a✝) x✝

Next tactic:
apply mul_comm
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
⊢ ∀ (a b : M →* G), a / b = a * b⁻¹

Next tactic:
intros
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
a✝ b✝ : M →* G
⊢ a✝ / b✝ = a✝ * b✝⁻¹

Next tactic:
ext
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      

Proof state:
case h
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
a✝ b✝ : M →* G
x✝ : M
⊢ (a✝ / b✝) x✝ = (a✝ * b✝⁻¹) x✝

Next tactic:
apply div_eq_mul_inv
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by 

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
n : ℤ
f : M →* G
⊢ (fun x => f x ^ n) 1 = 1

Next tactic:
simp
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by 

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
n : ℤ
f : M →* G
x y : M
⊢ OneHom.toFun { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) } (x * y) =
    OneHom.toFun { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) } x *
      OneHom.toFun { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) } y

Next tactic:
simp [mul_zpow]
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by simp [mul_zpow] },
    zpow_zero' := fun f => by
      

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
f : M →* G
⊢ (fun n f =>
        { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
          map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
      0 f =
    1

Next tactic:
ext x
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by simp [mul_zpow] },
    zpow_zero' := fun f => by
      ext x
      

Proof state:
case h
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
f : M →* G
x : M
⊢ ((fun n f =>
          { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
            map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
        0 f)
      x =
    1 x

Next tactic:
simp
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by simp [mul_zpow] },
    zpow_zero' := fun f => by
      ext x
      simp,
    zpow_succ' := fun n f => by
      

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
n : ℕ
f : M →* G
⊢ (fun n f =>
        { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
          map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
      (Int.ofNat (Nat.succ n)) f =
    f *
      (fun n f =>
          { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
            map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
        (Int.ofNat n) f

Next tactic:
ext x
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by simp [mul_zpow] },
    zpow_zero' := fun f => by
      ext x
      simp,
    zpow_succ' := fun n f => by
      ext x
      

Proof state:
case h
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
n : ℕ
f : M →* G
x : M
⊢ ((fun n f =>
          { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
            map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
        (Int.ofNat (Nat.succ n)) f)
      x =
    (f *
        (fun n f =>
            { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
              map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
          (Int.ofNat n) f)
      x

Next tactic:
simp [zpow_ofNat, pow_succ]
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by simp [mul_zpow] },
    zpow_zero' := fun f => by
      ext x
      simp,
    zpow_succ' := fun n f => by
      ext x
      simp [zpow_ofNat, pow_succ],
    zpow_neg' := fun n f => by
      

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
n : ℕ
f : M →* G
⊢ (fun n f =>
        { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
          map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
      (Int.negSucc n) f =
    ((fun n f =>
          { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
            map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
        (↑(Nat.succ n)) f)⁻¹

Next tactic:
ext x
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; apply mul_left_inv,
    zpow := fun n f =>
      { toFun := fun x => f x ^ n,
        map_one' := by simp,
        map_mul' := fun x y => by simp [mul_zpow] },
    zpow_zero' := fun f => by
      ext x
      simp,
    zpow_succ' := fun n f => by
      ext x
      simp [zpow_ofNat, pow_succ],
    zpow_neg' := fun n f => by
      ext x
      

Proof state:
case h
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
n : ℕ
f : M →* G
x : M
⊢ ((fun n f =>
          { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
            map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
        (Int.negSucc n) f)
      x =
    ((fun n f =>
            { toOneHom := { toFun := fun x => f x ^ n, map_one' := (_ : f 1 ^ n = 1) },
              map_mul' := (_ : ∀ (x y : M), f (x * y) ^ n = f x ^ n * f y ^ n) })
          (↑(Nat.succ n)) f)⁻¹
      x

Next tactic:
simp [Nat.succ_eq_add_one, zpow_ofNat, -Int.natCast_add]
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by 

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
⊢ ∀ (a : M →* G), a⁻¹ * a = 1

Next tactic:
intros
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; 

Proof state:
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
a✝ : M →* G
⊢ a✝⁻¹ * a✝ = 1

Next tactic:
ext
/-- If `G` is a commutative group, then `M →* G` is a commutative group too. -/
@[to_additive "If `G` is an additive commutative group, then `M →+ G` is an additive commutative
      group too."]
instance MonoidHom.commGroup {M G} [MulOneClass M] [CommGroup G] : CommGroup (M →* G) :=
  { MonoidHom.commMonoid with
    inv := Inv.inv,
    div := Div.div,
    div_eq_mul_inv := by
      intros
      ext
      apply div_eq_mul_inv,
    mul_left_inv := by intros; ext; 

Proof state:
case h
M✝ : Type uM
N : Type uN
P : Type uP
Q : Type uQ
M : Type ?u.6139
G : Type ?u.6142
inst✝¹ : MulOneClass M
inst✝ : CommGroup G
src✝ : CommMonoid (M →* G) := commMonoid
a✝ : M →* G
x✝ : M
⊢ (a✝⁻¹ * a✝) x✝ = 1 x✝

Next tactic:
apply mul_left_inv
/-- `flip` arguments of `f : M →* N →* P` -/
@[to_additive "`flip` arguments of `f : M →+ N →+ P`"]
def flip {mM : MulOneClass M} {mN : MulOneClass N} {mP : CommMonoid P} (f : M →* N →* P) :
    N →* M →* P where
  toFun y :=
    { toFun := fun x => f x y,
      map_one' := by 

Proof state:
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
mM : MulOneClass M
mN : MulOneClass N
mP : CommMonoid P
f : M →* N →* P
y : N
⊢ (fun x => (f x) y) 1 = 1

Next tactic:
simp [f.map_one, one_apply]
/-- `flip` arguments of `f : M →* N →* P` -/
@[to_additive "`flip` arguments of `f : M →+ N →+ P`"]
def flip {mM : MulOneClass M} {mN : MulOneClass N} {mP : CommMonoid P} (f : M →* N →* P) :
    N →* M →* P where
  toFun y :=
    { toFun := fun x => f x y,
      map_one' := by simp [f.map_one, one_apply],
      map_mul' := fun x₁ x₂ => by 

Proof state:
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
mM : MulOneClass M
mN : MulOneClass N
mP : CommMonoid P
f : M →* N →* P
y : N
x₁ x₂ : M
⊢ OneHom.toFun { toFun := fun x => (f x) y, map_one' := (_ : (f 1) y = 1) } (x₁ * x₂) =
    OneHom.toFun { toFun := fun x => (f x) y, map_one' := (_ : (f 1) y = 1) } x₁ *
      OneHom.toFun { toFun := fun x => (f x) y, map_one' := (_ : (f 1) y = 1) } x₂

Next tactic:
simp [f.map_mul, mul_apply]
/-- Composition of monoid morphisms (`MonoidHom.comp`) as a monoid morphism.

Note that unlike `MonoidHom.comp_hom'` this requires commutativity of `N`. -/
@[to_additive (attr := simps)
      "Composition of additive monoid morphisms (`AddMonoidHom.comp`) as an additive
      monoid morphism.

      Note that unlike `AddMonoidHom.comp_hom'` this requires commutativity of `N`.

      This also exists in a `LinearMap` version, `LinearMap.llcomp`."]
def compHom [MulOneClass M] [CommMonoid N] [CommMonoid P] :
    (N →* P) →* (M →* N) →* M →* P where
  toFun g := { toFun := g.comp, map_one' := comp_one g, map_mul' := comp_mul g }
  map_one' := by
    

Proof state:
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝² : MulOneClass M
inst✝¹ : CommMonoid N
inst✝ : CommMonoid P
⊢ (fun g =>
        { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
          map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
      1 =
    1

Next tactic:
ext1 f
/-- Composition of monoid morphisms (`MonoidHom.comp`) as a monoid morphism.

Note that unlike `MonoidHom.comp_hom'` this requires commutativity of `N`. -/
@[to_additive (attr := simps)
      "Composition of additive monoid morphisms (`AddMonoidHom.comp`) as an additive
      monoid morphism.

      Note that unlike `AddMonoidHom.comp_hom'` this requires commutativity of `N`.

      This also exists in a `LinearMap` version, `LinearMap.llcomp`."]
def compHom [MulOneClass M] [CommMonoid N] [CommMonoid P] :
    (N →* P) →* (M →* N) →* M →* P where
  toFun g := { toFun := g.comp, map_one' := comp_one g, map_mul' := comp_mul g }
  map_one' := by
    ext1 f
    

Proof state:
case h
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝² : MulOneClass M
inst✝¹ : CommMonoid N
inst✝ : CommMonoid P
f : M →* N
⊢ ((fun g =>
          { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
            map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
        1)
      f =
    1 f

Next tactic:
exact one_comp f
/-- Composition of monoid morphisms (`MonoidHom.comp`) as a monoid morphism.

Note that unlike `MonoidHom.comp_hom'` this requires commutativity of `N`. -/
@[to_additive (attr := simps)
      "Composition of additive monoid morphisms (`AddMonoidHom.comp`) as an additive
      monoid morphism.

      Note that unlike `AddMonoidHom.comp_hom'` this requires commutativity of `N`.

      This also exists in a `LinearMap` version, `LinearMap.llcomp`."]
def compHom [MulOneClass M] [CommMonoid N] [CommMonoid P] :
    (N →* P) →* (M →* N) →* M →* P where
  toFun g := { toFun := g.comp, map_one' := comp_one g, map_mul' := comp_mul g }
  map_one' := by
    ext1 f
    exact one_comp f
  map_mul' g₁ g₂ := by
    

Proof state:
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝² : MulOneClass M
inst✝¹ : CommMonoid N
inst✝ : CommMonoid P
g₁ g₂ : N →* P
⊢ OneHom.toFun
      {
        toFun := fun g =>
          { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
            map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) },
        map_one' :=
          (_ :
            (fun g =>
                  { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                    map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
                1 =
              1) }
      (g₁ * g₂) =
    OneHom.toFun
        {
          toFun := fun g =>
            { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
              map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) },
          map_one' :=
            (_ :
              (fun g =>
                    { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                      map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
                  1 =
                1) }
        g₁ *
      OneHom.toFun
        {
          toFun := fun g =>
            { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
              map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) },
          map_one' :=
            (_ :
              (fun g =>
                    { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                      map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
                  1 =
                1) }
        g₂

Next tactic:
ext1 f
/-- Composition of monoid morphisms (`MonoidHom.comp`) as a monoid morphism.

Note that unlike `MonoidHom.comp_hom'` this requires commutativity of `N`. -/
@[to_additive (attr := simps)
      "Composition of additive monoid morphisms (`AddMonoidHom.comp`) as an additive
      monoid morphism.

      Note that unlike `AddMonoidHom.comp_hom'` this requires commutativity of `N`.

      This also exists in a `LinearMap` version, `LinearMap.llcomp`."]
def compHom [MulOneClass M] [CommMonoid N] [CommMonoid P] :
    (N →* P) →* (M →* N) →* M →* P where
  toFun g := { toFun := g.comp, map_one' := comp_one g, map_mul' := comp_mul g }
  map_one' := by
    ext1 f
    exact one_comp f
  map_mul' g₁ g₂ := by
    ext1 f
    

Proof state:
case h
M : Type uM
N : Type uN
P : Type uP
Q : Type uQ
inst✝² : MulOneClass M
inst✝¹ : CommMonoid N
inst✝ : CommMonoid P
g₁ g₂ : N →* P
f : M →* N
⊢ (OneHom.toFun
        {
          toFun := fun g =>
            { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
              map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) },
          map_one' :=
            (_ :
              (fun g =>
                    { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                      map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
                  1 =
                1) }
        (g₁ * g₂))
      f =
    (OneHom.toFun
          {
            toFun := fun g =>
              { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) },
            map_one' :=
              (_ :
                (fun g =>
                      { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                        map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
                    1 =
                  1) }
          g₁ *
        OneHom.toFun
          {
            toFun := fun g =>
              { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) },
            map_one' :=
              (_ :
                (fun g =>
                      { toOneHom := { toFun := comp g, map_one' := (_ : comp g 1 = 1) },
                        map_mul' := (_ : ∀ (f₁ f₂ : M →* N), comp g (f₁ * f₂) = comp g f₁ * comp g f₂) })
                    1 =
                  1) }
          g₂)
      f

Next tactic:
exact mul_comp g₁ g₂ f
@[simp]
theorem toMatrix_self [DecidableEq ι] : b.toMatrix b = (1 : Matrix ι ι k) := by
  

Proof state:
ι : Type u₁
k : Type u₂
V : Type u₃
P : Type u₄
inst✝⁴ : AddCommGroup V
inst✝³ : AffineSpace V P
inst✝² : Ring k
inst✝¹ : Module k V
b : AffineBasis ι k P
inst✝ : DecidableEq ι
⊢ toMatrix b ⇑b = 1

Next tactic:
ext i j