l3lab/ntp-mathlib huggingface dataset:
/-- If the `Traversable t'` instance has the properties that `map`,
`map_const`, and `traverse` are equal to the ones that come from
carrying the traversable functor structure from `t` over the
equivalences, then the fact that `t` is a lawful traversable functor
carries over as well. -/
protected theorem isLawfulTraversable' [Traversable t']
    (h₀ : ∀ {α β} (f : α → β), map f = Equiv.map eqv f)
    (h₁ : ∀ {α β} (f : β), mapConst f = (Equiv.map eqv ∘ Function.const α) f)
    (h₂ :
      ∀ {F : Type u → Type u} [Applicative F],
        ∀ [LawfulApplicative F] {α β} (f : α → F β), traverse f = Equiv.traverse eqv f) :
    LawfulTraversable t' := by
  -- we can't use the same approach as for `lawful_functor'` because
  -- h₂ needs a `LawfulApplicative` assumption
  refine' { toLawfulFunctor := Equiv.lawfulFunctor' eqv @h₀ @h₁.. } <;> intros
  · rw [h₂, Equiv.id_traverse]
  · rw [h₂, Equiv.comp_traverse, h₂]
    congr
    rw [h₂]
  · rw [h₂, Equiv.traverse_eq_map_id, h₀]; rfl
  · 

Proof state:
case refine'_4
t t' : Type u → Type u
eqv : (α : Type u) → t α ≃ t' α
inst✝¹⁰ : Traversable t
inst✝⁹ : LawfulTraversable t
F G : Type u → Type u
inst✝⁸ : Applicative F
inst✝⁷ : Applicative G
inst✝⁶ : LawfulApplicative F
inst✝⁵ : LawfulApplicative G
η : ApplicativeTransformation F G
α β γ : Type u
inst✝⁴ : Traversable t'
h₀ : ∀ {α β : Type u} (f : α → β), map f = Equiv.map eqv f
h₁ : ∀ {α β : Type u} (f : β), mapConst f = (Equiv.map eqv ∘ Function.const α) f
h₂ :
  ∀ {F : Type u → Type u} [inst : Applicative F] [inst_1 : LawfulApplicative F] {α β : Type u} (f : α → F β),
    traverse f = Equiv.traverse eqv f
F✝ G✝ : Type u → Type u
inst✝³ : Applicative F✝
inst✝² : Applicative G✝
inst✝¹ : LawfulApplicative F✝
inst✝ : LawfulApplicative G✝
η✝ : ApplicativeTransformation F✝ G✝
α✝ β✝ : Type u
f✝ : α✝ → F✝ β✝
x✝ : t' α✝
⊢ (fun {α} => ApplicativeTransformation.app η✝ α) (traverse f✝ x✝) =
    traverse ((fun {α} => ApplicativeTransformation.app η✝ α) ∘ f✝) x✝

Next tactic:
rw [h₂, Equiv.naturality, h₂]
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by 

Proof state:
C : Type u
X Y Z : F C
⊢ Discrete.functor (normalizeObj (tensor (tensor X Y) Z)) ⟶ Discrete.functor (normalizeObj (tensor X (tensor Y Z)))

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; 

Proof state:
C : Type u
X Y Z : F C
⊢ (Discrete.functor fun x => normalizeObj Z (normalizeObj Y (normalizeObj X x).as).as) ⟶
    Discrete.functor fun x => normalizeObj Z (normalizeObj Y (normalizeObj X x).as).as

Next tactic:
exact Discrete.natTrans (fun _ => 𝟙 _)
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by 

Proof state:
C : Type u
X✝ Y✝ Z✝ : F C
⊢ Discrete.functor (normalizeObj (tensor X✝ (tensor Y✝ Z✝))) ⟶
    Discrete.functor (normalizeObj (tensor (tensor X✝ Y✝) Z✝))

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; 

Proof state:
C : Type u
X✝ Y✝ Z✝ : F C
⊢ (Discrete.functor fun x => normalizeObj Z✝ (normalizeObj Y✝ (normalizeObj X✝ x).as).as) ⟶
    Discrete.functor fun x => normalizeObj Z✝ (normalizeObj Y✝ (normalizeObj X✝ x).as).as

Next tactic:
exact Discrete.natTrans (fun _ => 𝟙 _)
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by 

Proof state:
C : Type u
a✝ : F C
⊢ Discrete.functor (normalizeObj (tensor unit a✝)) ⟶ Discrete.functor (normalizeObj a✝)

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; 

Proof state:
C : Type u
a✝ : F C
⊢ (Discrete.functor fun x => normalizeObj a✝ x) ⟶ Discrete.functor (normalizeObj a✝)

Next tactic:
exact Discrete.natTrans (fun _ => 𝟙 _)
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by 

Proof state:
C : Type u
a✝ : F C
⊢ Discrete.functor (normalizeObj a✝) ⟶ Discrete.functor (normalizeObj (tensor unit a✝))

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; 

Proof state:
C : Type u
a✝ : F C
⊢ Discrete.functor (normalizeObj a✝) ⟶ Discrete.functor fun x => normalizeObj a✝ x

Next tactic:
exact Discrete.natTrans (fun _ => 𝟙 _)
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_hom _ => by 

Proof state:
C : Type u
a✝ : F C
⊢ Discrete.functor (normalizeObj (tensor a✝ unit)) ⟶ Discrete.functor (normalizeObj a✝)

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_hom _ => by dsimp; 

Proof state:
C : Type u
a✝ : F C
⊢ (Discrete.functor fun x => { as := (normalizeObj a✝ x).as }) ⟶ Discrete.functor (normalizeObj a✝)

Next tactic:
exact Discrete.natTrans (fun _ => 𝟙 _)
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_inv _ => by 

Proof state:
C : Type u
a✝ : F C
⊢ Discrete.functor (normalizeObj a✝) ⟶ Discrete.functor (normalizeObj (tensor a✝ unit))

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_inv _ => by dsimp; 

Proof state:
C : Type u
a✝ : F C
⊢ Discrete.functor (normalizeObj a✝) ⟶ Discrete.functor fun x => { as := (normalizeObj a✝ x).as }

Next tactic:
exact Discrete.natTrans (fun _ => 𝟙 _)
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, (@comp _ _ _ _ f g) => normalizeMapAux f ≫ normalizeMapAux g
  | _, _, (@Hom.tensor _ T _ _ W f g) => by
    

Proof state:
C : Type u
T X✝ Y✝ W : F C
f : T ⟶ᵐ Y✝
g : X✝ ⟶ᵐ W
⊢ Discrete.functor (normalizeObj (tensor T X✝)) ⟶ Discrete.functor (normalizeObj (tensor Y✝ W))

Next tactic:
dsimp
/-- Auxiliary definition for `normalize`. Here we prove that objects that are related by
    associators and unitors map to the same normal form. -/
@[simp]
def normalizeMapAux :
    ∀ {X Y : F C}, (X ⟶ᵐ Y) →
      ((Discrete.functor (normalizeObj X) : _ ⥤ N C) ⟶ Discrete.functor (normalizeObj Y))
  | _, _, Hom.id _ => 𝟙 _
  | _, _, α_hom X Y Z => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, α_inv _ _ _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, l_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_hom _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, ρ_inv _ => by dsimp; exact Discrete.natTrans (fun _ => 𝟙 _)
  | _, _, (@comp _ _ _ _ f g) => normalizeMapAux f ≫ normalizeMapAux g
  | _, _, (@Hom.tensor _ T _ _ W f g) => by
    dsimp
    

Proof state:
C : Type u
T X✝ Y✝ W : F C
f : T ⟶ᵐ Y✝
g : X✝ ⟶ᵐ W
⊢ (Discrete.functor fun x => normalizeObj X✝ (normalizeObj T x).as) ⟶
    Discrete.functor fun x => normalizeObj W (normalizeObj Y✝ x).as

Next tactic:
exact Discrete.natTrans (fun ⟨X⟩ => (normalizeMapAux g).app (normalizeObj T X) ≫
      (Discrete.functor (normalizeObj W) : _ ⥤ N C).map ((normalizeMapAux f).app ⟨X⟩))
/-- Our normalization procedure works by first defining a functor `F C ⥤ (N C ⥤ N C)` (which turns
    out to be very easy), and then obtain a functor `F C ⥤ N C` by plugging in the normal object
    `𝟙_ C`. -/
@[simp]
def normalize : F C ⥤ N C ⥤ N C where
  obj X := Discrete.functor (normalizeObj X)
  map {X Y} := Quotient.lift normalizeMapAux (by 

Proof state:
C : Type u
X Y : F C
⊢ ∀ (a b : X ⟶ᵐ Y), a ≈ b → normalizeMapAux a = normalizeMapAux b

Next tactic:
aesop_cat
theorem tensorFunc_obj_map (Z : F C) {n n' : N C} (f : n ⟶ n') :
    ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z := by
  

Proof state:
C : Type u
Z : F C
n n' : (Discrete ∘ NormalMonoidalObject) C
f : n ⟶ n'
⊢ ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z

Next tactic:
cases n
theorem tensorFunc_obj_map (Z : F C) {n n' : N C} (f : n ⟶ n') :
    ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z := by
  cases n
  

Proof state:
case mk
C : Type u
Z : F C
n' : (Discrete ∘ NormalMonoidalObject) C
as✝ : NormalMonoidalObject C
f : { as := as✝ } ⟶ n'
⊢ ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z

Next tactic:
cases n'
theorem tensorFunc_obj_map (Z : F C) {n n' : N C} (f : n ⟶ n') :
    ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z := by
  cases n
  cases n'
  

Proof state:
case mk.mk
C : Type u
Z : F C
as✝¹ as✝ : NormalMonoidalObject C
f : { as := as✝¹ } ⟶ { as := as✝ }
⊢ ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z

Next tactic:
rcases f with ⟨⟨h⟩⟩
theorem tensorFunc_obj_map (Z : F C) {n n' : N C} (f : n ⟶ n') :
    ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z := by
  cases n
  cases n'
  rcases f with ⟨⟨h⟩⟩
  

Proof state:
case mk.mk.up.up
C : Type u
Z : F C
as✝¹ as✝ : NormalMonoidalObject C
h : { as := as✝¹ }.as = { as := as✝ }.as
⊢ ((tensorFunc C).obj Z).map { down := { down := h } } = inclusion.map { down := { down := h } } ⊗ 𝟙 Z

Next tactic:
dsimp at h
theorem tensorFunc_obj_map (Z : F C) {n n' : N C} (f : n ⟶ n') :
    ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z := by
  cases n
  cases n'
  rcases f with ⟨⟨h⟩⟩
  dsimp at h
  

Proof state:
case mk.mk.up.up
C : Type u
Z : F C
as✝¹ as✝ : NormalMonoidalObject C
h : as✝¹ = as✝
⊢ ((tensorFunc C).obj Z).map { down := { down := h } } = inclusion.map { down := { down := h } } ⊗ 𝟙 Z

Next tactic:
subst h
theorem tensorFunc_obj_map (Z : F C) {n n' : N C} (f : n ⟶ n') :
    ((tensorFunc C).obj Z).map f = inclusion.map f ⊗ 𝟙 Z := by
  cases n
  cases n'
  rcases f with ⟨⟨h⟩⟩
  dsimp at h
  subst h
  

Proof state:
case mk.mk.up.up
C : Type u
Z : F C
as✝ : NormalMonoidalObject C
⊢ ((tensorFunc C).obj Z).map { down := { down := (_ : as✝ = as✝) } } =
    inclusion.map { down := { down := (_ : as✝ = as✝) } } ⊗ 𝟙 Z

Next tactic:
simp
/-- Auxiliary definition for `normalizeIso`. -/
@[simp]
def normalizeIsoAux (X : F C) : (tensorFunc C).obj X ≅ (normalize' C).obj X :=
  NatIso.ofComponents (normalizeIsoApp C X)
    (by
      

Proof state:
C : Type u
X : F C
⊢ ∀ {X_1 Y : (Discrete ∘ NormalMonoidalObject) C} (f : X_1 ⟶ Y),
    ((tensorFunc C).obj X).map f ≫ (normalizeIsoApp C X Y).hom =
      (normalizeIsoApp C X X_1).hom ≫ ((normalize' C).obj X).map f

Next tactic:
rintro ⟨X⟩ ⟨Y⟩ ⟨⟨f⟩⟩
/-- Auxiliary definition for `normalizeIso`. -/
@[simp]
def normalizeIsoAux (X : F C) : (tensorFunc C).obj X ≅ (normalize' C).obj X :=
  NatIso.ofComponents (normalizeIsoApp C X)
    (by
      rintro ⟨X⟩ ⟨Y⟩ ⟨⟨f⟩⟩
      

Proof state:
case mk.mk.up.up
C : Type u
X✝ : F C
X Y : NormalMonoidalObject C
f : { as := X }.as = { as := Y }.as
⊢ ((tensorFunc C).obj X✝).map { down := { down := f } } ≫ (normalizeIsoApp C X✝ { as := Y }).hom =
    (normalizeIsoApp C X✝ { as := X }).hom ≫ ((normalize' C).obj X✝).map { down := { down := f } }

Next tactic:
dsimp at f
/-- Auxiliary definition for `normalizeIso`. -/
@[simp]
def normalizeIsoAux (X : F C) : (tensorFunc C).obj X ≅ (normalize' C).obj X :=
  NatIso.ofComponents (normalizeIsoApp C X)
    (by
      rintro ⟨X⟩ ⟨Y⟩ ⟨⟨f⟩⟩
      dsimp at f
      

Proof state:
case mk.mk.up.up
C : Type u
X✝ : F C
X Y : NormalMonoidalObject C
f : X = Y
⊢ ((tensorFunc C).obj X✝).map { down := { down := f } } ≫ (normalizeIsoApp C X✝ { as := Y }).hom =
    (normalizeIsoApp C X✝ { as := X }).hom ≫ ((normalize' C).obj X✝).map { down := { down := f } }

Next tactic:
subst f
/-- Auxiliary definition for `normalizeIso`. -/
@[simp]
def normalizeIsoAux (X : F C) : (tensorFunc C).obj X ≅ (normalize' C).obj X :=
  NatIso.ofComponents (normalizeIsoApp C X)
    (by
      rintro ⟨X⟩ ⟨Y⟩ ⟨⟨f⟩⟩
      dsimp at f
      subst f
      

Proof state:
case mk.mk.up.up
C : Type u
X✝ : F C
X : NormalMonoidalObject C
⊢ ((tensorFunc C).obj X✝).map { down := { down := (_ : X = X) } } ≫ (normalizeIsoApp C X✝ { as := X }).hom =
    (normalizeIsoApp C X✝ { as := X }).hom ≫ ((normalize' C).obj X✝).map { down := { down := (_ : X = X) } }

Next tactic:
dsimp
/-- Auxiliary definition for `normalizeIso`. -/
@[simp]
def normalizeIsoAux (X : F C) : (tensorFunc C).obj X ≅ (normalize' C).obj X :=
  NatIso.ofComponents (normalizeIsoApp C X)
    (by
      rintro ⟨X⟩ ⟨Y⟩ ⟨⟨f⟩⟩
      dsimp at f
      subst f
      dsimp
      

Proof state:
case mk.mk.up.up
C : Type u
X✝ : F C
X : NormalMonoidalObject C
⊢ (Discrete.functor fun n => inclusionObj n ⊗ X✝).map { down := { down := (_ : X = X) } } ≫
      (normalizeIsoApp C X✝ { as := X }).hom =
    (normalizeIsoApp C X✝ { as := X }).hom ≫
      (((whiskeringRight (Discrete (NormalMonoidalObject C)) (Discrete (NormalMonoidalObject C)) (F C)).obj
                (Discrete.functor inclusionObj)).obj
            (Discrete.functor (normalizeObj X✝))).map
        { down := { down := (_ : X = X) } }

Next tactic:
simp
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      

Proof state:
C : Type u
⊢ ∀ {X Y : F C} (f : X ⟶ Y),
    (tensorFunc C).map f ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map f

Next tactic:
rintro X Y f
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      

Proof state:
C : Type u
X Y : F C
f : X ⟶ Y
⊢ (tensorFunc C).map f ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map f

Next tactic:
induction' f using Quotient.recOn with f
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; 

Proof state:
case f
C : Type u
X Y : F C
f : X ⟶ᵐ Y
⊢ (tensorFunc C).map ⟦f⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦f⟧
case h
C : Type u
X Y : F C
f : X ⟶ Y
a✝ b✝ : X ⟶ᵐ Y
p✝ : a✝ ≈ b✝
⊢ (_ : (tensorFunc C).map ⟦b✝⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦b✝⟧) =
    (_ : (tensorFunc C).map ⟦b✝⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦b✝⟧)

Next tactic:
swap
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; 

Proof state:
case h
C : Type u
X Y : F C
f : X ⟶ Y
a✝ b✝ : X ⟶ᵐ Y
p✝ : a✝ ≈ b✝
⊢ (_ : (tensorFunc C).map ⟦b✝⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦b✝⟧) =
    (_ : (tensorFunc C).map ⟦b✝⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦b✝⟧)
case f
C : Type u
X Y : F C
f : X ⟶ᵐ Y
⊢ (tensorFunc C).map ⟦f⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦f⟧

Next tactic:
rfl
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; rfl
      

Proof state:
case f
C : Type u
X Y : F C
f : X ⟶ᵐ Y
⊢ (tensorFunc C).map ⟦f⟧ ≫ (normalizeIsoAux C Y).hom = (normalizeIsoAux C X).hom ≫ (normalize' C).map ⟦f⟧

Next tactic:
induction' f with _ X₁ X₂ X₃ _ _ _ _ _ _ _ _ _ _ _ _ h₁ h₂ X₁ X₂ Y₁ Y₂ f g h₁ h₂
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; rfl
      induction' f with _ X₁ X₂ X₃ _ _ _ _ _ _ _ _ _ _ _ _ h₁ h₂ X₁ X₂ Y₁ Y₂ f g h₁ h₂
      · 

Proof state:
case f.id
C : Type u
X Y X✝ : F C
⊢ (tensorFunc C).map ⟦Hom.id X✝⟧ ≫ (normalizeIsoAux C X✝).hom =
    (normalizeIsoAux C X✝).hom ≫ (normalize' C).map ⟦Hom.id X✝⟧

Next tactic:
simp only [mk_id, Functor.map_id, Category.comp_id, Category.id_comp]
/-- The isomorphism between `n ⊗ X` and `normalize X n` is natural (in both `X` and `n`, but
    naturality in `n` is trivial and was "proved" in `normalizeIsoAux`). This is the real heart
    of our proof of the coherence theorem. -/
def normalizeIso : tensorFunc C ≅ normalize' C :=
  NatIso.ofComponents (normalizeIsoAux C)
    (by -- porting note: the proof has been mostly rewritten
      rintro X Y f
      induction' f using Quotient.recOn with f; swap; rfl
      induction' f with _ X₁ X₂ X₃ _ _ _ _ _ _ _ _ _ _ _ _ h₁ h₂ X₁ X₂ Y₁ Y₂ f g h₁ h₂
      · simp only [mk_id, Functor.map_id, Category.comp_id, Category.id_comp]
      · 

Proof state:
case f.α_hom
C : Type u
X Y X₁ X₂ X₃ : F C
⊢ (tensorFunc C).map ⟦Hom.α_hom X₁ X₂ X₃⟧ ≫ (normalizeIsoAux C (tensor X₁ (tensor X₂ X₃))).hom =
    (normalizeIsoAux C (tensor (tensor X₁ X₂) X₃)).hom ≫ (normalize' C).map ⟦Hom.α_hom X₁ X₂ X₃⟧

Next tactic:
ext n