l3lab/ntp-mathlib huggingface dataset:
/-- An equivalent condition for a map of presheaves to be locally surjective
is for all the induced maps on stalks to be surjective. -/
theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) :
    IsLocallySurjective T ↔ ∀ x : X, Function.Surjective ((stalkFunctor C x).map T) := by
  constructor <;> intro hT
  · /- human proof:
        Let g ∈ Γₛₜ 𝒢 x be a germ. Represent it on an open set U ⊆ X
        as ⟨t, U⟩. By local surjectivity, pass to a smaller open set V
        on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
        Then the germ of s maps to g -/
    -- Let g ∈ Γₛₜ 𝒢 x be a germ.
    intro x g
    -- Represent it on an open set U ⊆ X as ⟨t, U⟩.
    obtain ⟨U, hxU, t, rfl⟩ := 𝒢.germ_exist x g
    -- By local surjectivity, pass to a smaller open set V
    -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
    rcases hT U t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩
    -- Then the germ of s maps to g.
    use ℱ.germ ⟨x, hxV⟩ s
    -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative
    -- to lean 3.
    convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1
    simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm
  · /- human proof:
        Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point.
        By surjectivity on stalks, the germ of t is the image of
        some germ f ∈ Γₛₜ ℱ x. Represent f on some open set V ⊆ X as ⟨s, V⟩.
        Then there is some possibly smaller open set x ∈ W ⊆ V ∩ U on which
        we have T(s) |_ W = t |_ W. -/
    intro U t x hxU
    set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x
    obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x
    obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x
    -- rfl : ℱ.germ x s = s_x
    have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by
      convert hs_x using 1
      

Proof state:
case h.e'_2.h
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
X : TopCat
ℱ 𝒢 : Presheaf C X
inst✝¹ : Limits.HasColimits C
inst✝ : Limits.PreservesFilteredColimits (forget C)
T : ℱ ⟶ 𝒢
hT : ∀ (x : ↑X), Function.Surjective ⇑((stalkFunctor C x).map T)
U : Opens ↑X
t : (forget C).obj (𝒢.obj (op U))
x : ↑X
hxU : x ∈ U
t_x : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxU }) := (germ 𝒢 { val := x, property := hxU }) t
ht_x : t_x = (germ 𝒢 { val := x, property := hxU }) t
V : Opens ↑X
hxV : x ∈ V
s : (forget C).obj (ℱ.obj (op V))
hs_x : ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) = t_x
e_1✝ : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxV }) = (forget C).obj ((stalkFunctor C x).obj 𝒢)
⊢ (germ 𝒢 { val := x, property := hxV }) ((T.app (op V)) s) =
    ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s)

Next tactic:
symm
/-- An equivalent condition for a map of presheaves to be locally surjective
is for all the induced maps on stalks to be surjective. -/
theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) :
    IsLocallySurjective T ↔ ∀ x : X, Function.Surjective ((stalkFunctor C x).map T) := by
  constructor <;> intro hT
  · /- human proof:
        Let g ∈ Γₛₜ 𝒢 x be a germ. Represent it on an open set U ⊆ X
        as ⟨t, U⟩. By local surjectivity, pass to a smaller open set V
        on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
        Then the germ of s maps to g -/
    -- Let g ∈ Γₛₜ 𝒢 x be a germ.
    intro x g
    -- Represent it on an open set U ⊆ X as ⟨t, U⟩.
    obtain ⟨U, hxU, t, rfl⟩ := 𝒢.germ_exist x g
    -- By local surjectivity, pass to a smaller open set V
    -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
    rcases hT U t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩
    -- Then the germ of s maps to g.
    use ℱ.germ ⟨x, hxV⟩ s
    -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative
    -- to lean 3.
    convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1
    simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm
  · /- human proof:
        Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point.
        By surjectivity on stalks, the germ of t is the image of
        some germ f ∈ Γₛₜ ℱ x. Represent f on some open set V ⊆ X as ⟨s, V⟩.
        Then there is some possibly smaller open set x ∈ W ⊆ V ∩ U on which
        we have T(s) |_ W = t |_ W. -/
    intro U t x hxU
    set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x
    obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x
    obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x
    -- rfl : ℱ.germ x s = s_x
    have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by
      convert hs_x using 1
      symm
      

Proof state:
case h.e'_2.h
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
X : TopCat
ℱ 𝒢 : Presheaf C X
inst✝¹ : Limits.HasColimits C
inst✝ : Limits.PreservesFilteredColimits (forget C)
T : ℱ ⟶ 𝒢
hT : ∀ (x : ↑X), Function.Surjective ⇑((stalkFunctor C x).map T)
U : Opens ↑X
t : (forget C).obj (𝒢.obj (op U))
x : ↑X
hxU : x ∈ U
t_x : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxU }) := (germ 𝒢 { val := x, property := hxU }) t
ht_x : t_x = (germ 𝒢 { val := x, property := hxU }) t
V : Opens ↑X
hxV : x ∈ V
s : (forget C).obj (ℱ.obj (op V))
hs_x : ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) = t_x
e_1✝ : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxV }) = (forget C).obj ((stalkFunctor C x).obj 𝒢)
⊢ ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) =
    (germ 𝒢 { val := x, property := hxV }) ((T.app (op V)) s)

Next tactic:
convert stalkFunctor_map_germ_apply _ _ _ s
/-- An equivalent condition for a map of presheaves to be locally surjective
is for all the induced maps on stalks to be surjective. -/
theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) :
    IsLocallySurjective T ↔ ∀ x : X, Function.Surjective ((stalkFunctor C x).map T) := by
  constructor <;> intro hT
  · /- human proof:
        Let g ∈ Γₛₜ 𝒢 x be a germ. Represent it on an open set U ⊆ X
        as ⟨t, U⟩. By local surjectivity, pass to a smaller open set V
        on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
        Then the germ of s maps to g -/
    -- Let g ∈ Γₛₜ 𝒢 x be a germ.
    intro x g
    -- Represent it on an open set U ⊆ X as ⟨t, U⟩.
    obtain ⟨U, hxU, t, rfl⟩ := 𝒢.germ_exist x g
    -- By local surjectivity, pass to a smaller open set V
    -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
    rcases hT U t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩
    -- Then the germ of s maps to g.
    use ℱ.germ ⟨x, hxV⟩ s
    -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative
    -- to lean 3.
    convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1
    simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm
  · /- human proof:
        Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point.
        By surjectivity on stalks, the germ of t is the image of
        some germ f ∈ Γₛₜ ℱ x. Represent f on some open set V ⊆ X as ⟨s, V⟩.
        Then there is some possibly smaller open set x ∈ W ⊆ V ∩ U on which
        we have T(s) |_ W = t |_ W. -/
    intro U t x hxU
    set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x
    obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x
    obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x
    -- rfl : ℱ.germ x s = s_x
    have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by
      convert hs_x using 1
      symm
      convert stalkFunctor_map_germ_apply _ _ _ s
    

Proof state:
case mpr.intro.intro.intro.intro
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
X : TopCat
ℱ 𝒢 : Presheaf C X
inst✝¹ : Limits.HasColimits C
inst✝ : Limits.PreservesFilteredColimits (forget C)
T : ℱ ⟶ 𝒢
hT : ∀ (x : ↑X), Function.Surjective ⇑((stalkFunctor C x).map T)
U : Opens ↑X
t : (forget C).obj (𝒢.obj (op U))
x : ↑X
hxU : x ∈ U
t_x : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxU }) := (germ 𝒢 { val := x, property := hxU }) t
ht_x : t_x = (germ 𝒢 { val := x, property := hxU }) t
V : Opens ↑X
hxV : x ∈ V
s : (forget C).obj (ℱ.obj (op V))
hs_x : ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) = t_x
key_W : ∃ W, ∃ (_ : x ∈ W), ∃ iU iV, (𝒢.map iU.op) ((T.app (op V)) s) = (𝒢.map iV.op) t
⊢ ∃ U_1 f, (imageSieve T t).arrows f ∧ x ∈ U_1

Next tactic:
obtain ⟨W, hxW, hWV, hWU, h_eq⟩ := key_W
/-- An equivalent condition for a map of presheaves to be locally surjective
is for all the induced maps on stalks to be surjective. -/
theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) :
    IsLocallySurjective T ↔ ∀ x : X, Function.Surjective ((stalkFunctor C x).map T) := by
  constructor <;> intro hT
  · /- human proof:
        Let g ∈ Γₛₜ 𝒢 x be a germ. Represent it on an open set U ⊆ X
        as ⟨t, U⟩. By local surjectivity, pass to a smaller open set V
        on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
        Then the germ of s maps to g -/
    -- Let g ∈ Γₛₜ 𝒢 x be a germ.
    intro x g
    -- Represent it on an open set U ⊆ X as ⟨t, U⟩.
    obtain ⟨U, hxU, t, rfl⟩ := 𝒢.germ_exist x g
    -- By local surjectivity, pass to a smaller open set V
    -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
    rcases hT U t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩
    -- Then the germ of s maps to g.
    use ℱ.germ ⟨x, hxV⟩ s
    -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative
    -- to lean 3.
    convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1
    simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm
  · /- human proof:
        Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point.
        By surjectivity on stalks, the germ of t is the image of
        some germ f ∈ Γₛₜ ℱ x. Represent f on some open set V ⊆ X as ⟨s, V⟩.
        Then there is some possibly smaller open set x ∈ W ⊆ V ∩ U on which
        we have T(s) |_ W = t |_ W. -/
    intro U t x hxU
    set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x
    obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x
    obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x
    -- rfl : ℱ.germ x s = s_x
    have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by
      convert hs_x using 1
      symm
      convert stalkFunctor_map_germ_apply _ _ _ s
    obtain ⟨W, hxW, hWV, hWU, h_eq⟩ := key_W
    

Proof state:
case mpr.intro.intro.intro.intro.intro.intro.intro.intro
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
X : TopCat
ℱ 𝒢 : Presheaf C X
inst✝¹ : Limits.HasColimits C
inst✝ : Limits.PreservesFilteredColimits (forget C)
T : ℱ ⟶ 𝒢
hT : ∀ (x : ↑X), Function.Surjective ⇑((stalkFunctor C x).map T)
U : Opens ↑X
t : (forget C).obj (𝒢.obj (op U))
x : ↑X
hxU : x ∈ U
t_x : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxU }) := (germ 𝒢 { val := x, property := hxU }) t
ht_x : t_x = (germ 𝒢 { val := x, property := hxU }) t
V : Opens ↑X
hxV : x ∈ V
s : (forget C).obj (ℱ.obj (op V))
hs_x : ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) = t_x
W : Opens ↑X
hxW : x ∈ W
hWV : W ⟶ V
hWU : W ⟶ U
h_eq : (𝒢.map hWV.op) ((T.app (op V)) s) = (𝒢.map hWU.op) t
⊢ ∃ U_1 f, (imageSieve T t).arrows f ∧ x ∈ U_1

Next tactic:
refine' ⟨W, hWU, ⟨ℱ.map hWV.op s, _⟩, hxW⟩
/-- An equivalent condition for a map of presheaves to be locally surjective
is for all the induced maps on stalks to be surjective. -/
theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) :
    IsLocallySurjective T ↔ ∀ x : X, Function.Surjective ((stalkFunctor C x).map T) := by
  constructor <;> intro hT
  · /- human proof:
        Let g ∈ Γₛₜ 𝒢 x be a germ. Represent it on an open set U ⊆ X
        as ⟨t, U⟩. By local surjectivity, pass to a smaller open set V
        on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
        Then the germ of s maps to g -/
    -- Let g ∈ Γₛₜ 𝒢 x be a germ.
    intro x g
    -- Represent it on an open set U ⊆ X as ⟨t, U⟩.
    obtain ⟨U, hxU, t, rfl⟩ := 𝒢.germ_exist x g
    -- By local surjectivity, pass to a smaller open set V
    -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
    rcases hT U t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩
    -- Then the germ of s maps to g.
    use ℱ.germ ⟨x, hxV⟩ s
    -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative
    -- to lean 3.
    convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1
    simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm
  · /- human proof:
        Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point.
        By surjectivity on stalks, the germ of t is the image of
        some germ f ∈ Γₛₜ ℱ x. Represent f on some open set V ⊆ X as ⟨s, V⟩.
        Then there is some possibly smaller open set x ∈ W ⊆ V ∩ U on which
        we have T(s) |_ W = t |_ W. -/
    intro U t x hxU
    set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x
    obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x
    obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x
    -- rfl : ℱ.germ x s = s_x
    have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by
      convert hs_x using 1
      symm
      convert stalkFunctor_map_germ_apply _ _ _ s
    obtain ⟨W, hxW, hWV, hWU, h_eq⟩ := key_W
    refine' ⟨W, hWU, ⟨ℱ.map hWV.op s, _⟩, hxW⟩
    

Proof state:
case mpr.intro.intro.intro.intro.intro.intro.intro.intro
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
X : TopCat
ℱ 𝒢 : Presheaf C X
inst✝¹ : Limits.HasColimits C
inst✝ : Limits.PreservesFilteredColimits (forget C)
T : ℱ ⟶ 𝒢
hT : ∀ (x : ↑X), Function.Surjective ⇑((stalkFunctor C x).map T)
U : Opens ↑X
t : (forget C).obj (𝒢.obj (op U))
x : ↑X
hxU : x ∈ U
t_x : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxU }) := (germ 𝒢 { val := x, property := hxU }) t
ht_x : t_x = (germ 𝒢 { val := x, property := hxU }) t
V : Opens ↑X
hxV : x ∈ V
s : (forget C).obj (ℱ.obj (op V))
hs_x : ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) = t_x
W : Opens ↑X
hxW : x ∈ W
hWV : W ⟶ V
hWU : W ⟶ U
h_eq : (𝒢.map hWV.op) ((T.app (op V)) s) = (𝒢.map hWU.op) t
⊢ (T.app (op W)) ((ℱ.map hWV.op) s) = (𝒢.map hWU.op) t

Next tactic:
convert h_eq using 1
/-- An equivalent condition for a map of presheaves to be locally surjective
is for all the induced maps on stalks to be surjective. -/
theorem locally_surjective_iff_surjective_on_stalks (T : ℱ ⟶ 𝒢) :
    IsLocallySurjective T ↔ ∀ x : X, Function.Surjective ((stalkFunctor C x).map T) := by
  constructor <;> intro hT
  · /- human proof:
        Let g ∈ Γₛₜ 𝒢 x be a germ. Represent it on an open set U ⊆ X
        as ⟨t, U⟩. By local surjectivity, pass to a smaller open set V
        on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
        Then the germ of s maps to g -/
    -- Let g ∈ Γₛₜ 𝒢 x be a germ.
    intro x g
    -- Represent it on an open set U ⊆ X as ⟨t, U⟩.
    obtain ⟨U, hxU, t, rfl⟩ := 𝒢.germ_exist x g
    -- By local surjectivity, pass to a smaller open set V
    -- on which there exists s ∈ Γ_ ℱ V mapping to t |_ V.
    rcases hT U t x hxU with ⟨V, ι, ⟨s, h_eq⟩, hxV⟩
    -- Then the germ of s maps to g.
    use ℱ.germ ⟨x, hxV⟩ s
    -- Porting note: `convert` went too deep and swapped LHS and RHS of the remaining goal relative
    -- to lean 3.
    convert stalkFunctor_map_germ_apply V ⟨x, hxV⟩ T s using 1
    simpa [h_eq] using (germ_res_apply 𝒢 ι ⟨x, hxV⟩ t).symm
  · /- human proof:
        Let U be an open set, t ∈ Γ ℱ U a section, x ∈ U a point.
        By surjectivity on stalks, the germ of t is the image of
        some germ f ∈ Γₛₜ ℱ x. Represent f on some open set V ⊆ X as ⟨s, V⟩.
        Then there is some possibly smaller open set x ∈ W ⊆ V ∩ U on which
        we have T(s) |_ W = t |_ W. -/
    intro U t x hxU
    set t_x := 𝒢.germ ⟨x, hxU⟩ t with ht_x
    obtain ⟨s_x, hs_x : ((stalkFunctor C x).map T) s_x = t_x⟩ := hT x t_x
    obtain ⟨V, hxV, s, rfl⟩ := ℱ.germ_exist x s_x
    -- rfl : ℱ.germ x s = s_x
    have key_W := 𝒢.germ_eq x hxV hxU (T.app _ s) t <| by
      convert hs_x using 1
      symm
      convert stalkFunctor_map_germ_apply _ _ _ s
    obtain ⟨W, hxW, hWV, hWU, h_eq⟩ := key_W
    refine' ⟨W, hWU, ⟨ℱ.map hWV.op s, _⟩, hxW⟩
    convert h_eq using 1
    

Proof state:
case h.e'_2
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
X : TopCat
ℱ 𝒢 : Presheaf C X
inst✝¹ : Limits.HasColimits C
inst✝ : Limits.PreservesFilteredColimits (forget C)
T : ℱ ⟶ 𝒢
hT : ∀ (x : ↑X), Function.Surjective ⇑((stalkFunctor C x).map T)
U : Opens ↑X
t : (forget C).obj (𝒢.obj (op U))
x : ↑X
hxU : x ∈ U
t_x : (forget C).obj (stalk 𝒢 ↑{ val := x, property := hxU }) := (germ 𝒢 { val := x, property := hxU }) t
ht_x : t_x = (germ 𝒢 { val := x, property := hxU }) t
V : Opens ↑X
hxV : x ∈ V
s : (forget C).obj (ℱ.obj (op V))
hs_x : ((stalkFunctor C x).map T) ((germ ℱ { val := x, property := hxV }) s) = t_x
W : Opens ↑X
hxW : x ∈ W
hWV : W ⟶ V
hWU : W ⟶ U
h_eq : (𝒢.map hWV.op) ((T.app (op V)) s) = (𝒢.map hWU.op) t
⊢ (T.app (op W)) ((ℱ.map hWV.op) s) = (𝒢.map hWV.op) ((T.app (op V)) s)

Next tactic:
simp only [← comp_apply, T.naturality]
theorem congr_app {F G : C ⥤ D} {α β : NatTrans F G} (h : α = β) (X : C) : α.app X = β.app X := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
α β : F.NatTrans G
h : α = β
X : C
⊢ NatTrans.app α X = NatTrans.app β X

Next tactic:
aesop_cat
/-- The diagram
    F(f)      F(g)      F(h)
F X ----> F Y ----> F U ----> F U
 |         |         |         |
 | α(X)    | α(Y)    | α(U)    | α(V)
 v         v         v         v
G X ----> G Y ----> G U ----> G V
    G(f)      G(g)      G(h)
commutes.
-/
example {F G : C ⥤ D} (α : NatTrans F G) {X Y U V : C} (f : X ⟶ Y) (g : Y ⟶ U) (h : U ⟶ V) :
    α.app X ≫ G.map f ≫ G.map g ≫ G.map h = F.map f ≫ F.map g ≫ F.map h ≫ α.app V := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
F G : C ⥤ D
α : F.NatTrans G
X Y U V : C
f : X ⟶ Y
g : Y ⟶ U
h : U ⟶ V
⊢ α.app X ≫ G.map f ≫ G.map g ≫ G.map h = F.map f ≫ F.map g ≫ F.map h ≫ α.app V

Next tactic:
simp
@[simps]
instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F where
  ε :=
    limit.lift _
      { pt := _
        π := { app := fun j => 𝟙 _ } }
  μ F G :=
    limit.lift (F ⊗ G)
      { pt := limit F ⊗ limit G
        π :=
          { app := fun j => limit.π F j ⊗ limit.π G j
            naturality := fun j j' f => by
              

Proof state:
J : Type v
inst✝³ : SmallCategory J
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasLimits C
inst✝ : MonoidalCategory C
F G : J ⥤ C
j j' : J
f : j ⟶ j'
⊢ ((Functor.const J).obj (limit F ⊗ limit G)).map f ≫ (fun j => limit.π F j ⊗ limit.π G j) j' =
    (fun j => limit.π F j ⊗ limit.π G j) j ≫ (F ⊗ G).map f

Next tactic:
dsimp
@[simps]
instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F where
  ε :=
    limit.lift _
      { pt := _
        π := { app := fun j => 𝟙 _ } }
  μ F G :=
    limit.lift (F ⊗ G)
      { pt := limit F ⊗ limit G
        π :=
          { app := fun j => limit.π F j ⊗ limit.π G j
            naturality := fun j j' f => by
              dsimp
              

Proof state:
J : Type v
inst✝³ : SmallCategory J
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasLimits C
inst✝ : MonoidalCategory C
F G : J ⥤ C
j j' : J
f : j ⟶ j'
⊢ 𝟙 (limit F ⊗ limit G) ≫ (limit.π F j' ⊗ limit.π G j') = (limit.π F j ⊗ limit.π G j) ≫ (F.map f ⊗ G.map f)

Next tactic:
simp only [Category.id_comp, ← tensor_comp, limit.w]
@[simps]
instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F where
  ε :=
    limit.lift _
      { pt := _
        π := { app := fun j => 𝟙 _ } }
  μ F G :=
    limit.lift (F ⊗ G)
      { pt := limit F ⊗ limit G
        π :=
          { app := fun j => limit.π F j ⊗ limit.π G j
            naturality := fun j j' f => by
              dsimp
              simp only [Category.id_comp, ← tensor_comp, limit.w] } }
  μ_natural f g := by
    

Proof state:
J : Type v
inst✝³ : SmallCategory J
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasLimits C
inst✝ : MonoidalCategory C
X✝ Y✝ X'✝ Y'✝ : J ⥤ C
f : X✝ ⟶ Y✝
g : X'✝ ⟶ Y'✝
⊢ (map (fun F => limit F) f ⊗ map (fun F => limit F) g) ≫
      (fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j })
        Y✝ Y'✝ =
    (fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j }) X✝
        X'✝ ≫
      map (fun F => limit F) (f ⊗ g)

Next tactic:
ext
@[simps]
instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F where
  ε :=
    limit.lift _
      { pt := _
        π := { app := fun j => 𝟙 _ } }
  μ F G :=
    limit.lift (F ⊗ G)
      { pt := limit F ⊗ limit G
        π :=
          { app := fun j => limit.π F j ⊗ limit.π G j
            naturality := fun j j' f => by
              dsimp
              simp only [Category.id_comp, ← tensor_comp, limit.w] } }
  μ_natural f g := by
    ext; 

Proof state:
case w
J : Type v
inst✝³ : SmallCategory J
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasLimits C
inst✝ : MonoidalCategory C
X✝ Y✝ X'✝ Y'✝ : J ⥤ C
f : X✝ ⟶ Y✝
g : X'✝ ⟶ Y'✝
j✝ : J
⊢ ((map (fun F => limit F) f ⊗ map (fun F => limit F) g) ≫
        (fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j })
          Y✝ Y'✝) ≫
      limit.π (Y✝ ⊗ Y'✝) j✝ =
    ((fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j }) X✝
          X'✝ ≫
        map (fun F => limit F) (f ⊗ g)) ≫
      limit.π (Y✝ ⊗ Y'✝) j✝

Next tactic:
dsimp
@[simps]
instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F where
  ε :=
    limit.lift _
      { pt := _
        π := { app := fun j => 𝟙 _ } }
  μ F G :=
    limit.lift (F ⊗ G)
      { pt := limit F ⊗ limit G
        π :=
          { app := fun j => limit.π F j ⊗ limit.π G j
            naturality := fun j j' f => by
              dsimp
              simp only [Category.id_comp, ← tensor_comp, limit.w] } }
  μ_natural f g := by
    ext; dsimp
    

Proof state:
case w
J : Type v
inst✝³ : SmallCategory J
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasLimits C
inst✝ : MonoidalCategory C
X✝ Y✝ X'✝ Y'✝ : J ⥤ C
f : X✝ ⟶ Y✝
g : X'✝ ⟶ Y'✝
j✝ : J
⊢ ((limMap f ⊗ limMap g) ≫
        limit.lift (Y✝ ⊗ Y'✝) { pt := limit Y✝ ⊗ limit Y'✝, π := NatTrans.mk fun j => limit.π Y✝ j ⊗ limit.π Y'✝ j }) ≫
      limit.π (Y✝ ⊗ Y'✝) j✝ =
    (limit.lift (X✝ ⊗ X'✝) { pt := limit X✝ ⊗ limit X'✝, π := NatTrans.mk fun j => limit.π X✝ j ⊗ limit.π X'✝ j } ≫
        limMap (f ⊗ g)) ≫
      limit.π (Y✝ ⊗ Y'✝) j✝

Next tactic:
simp only [limit.lift_π, Cones.postcompose_obj_π, Monoidal.tensorHom_app, limit.lift_map,
      NatTrans.comp_app, Category.assoc, ← tensor_comp, limMap_π]
@[simps]
instance limitLaxMonoidal : LaxMonoidal fun F : J ⥤ C => limit F where
  ε :=
    limit.lift _
      { pt := _
        π := { app := fun j => 𝟙 _ } }
  μ F G :=
    limit.lift (F ⊗ G)
      { pt := limit F ⊗ limit G
        π :=
          { app := fun j => limit.π F j ⊗ limit.π G j
            naturality := fun j j' f => by
              dsimp
              simp only [Category.id_comp, ← tensor_comp, limit.w] } }
  μ_natural f g := by
    ext; dsimp
    simp only [limit.lift_π, Cones.postcompose_obj_π, Monoidal.tensorHom_app, limit.lift_map,
      NatTrans.comp_app, Category.assoc, ← tensor_comp, limMap_π]
  associativity X Y Z := by
    

Proof state:
J : Type v
inst✝³ : SmallCategory J
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasLimits C
inst✝ : MonoidalCategory C
X Y Z : J ⥤ C
⊢ ((fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j }) X
          Y ⊗
        𝟙 (limit Z)) ≫
      (fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j })
          (X ⊗ Y) Z ≫
        map (fun F => limit F) (α_ X Y Z).hom =
    (α_ (limit X) (limit Y) (limit Z)).hom ≫
      (𝟙 (limit X) ⊗
          (fun F G =>
              limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j })
            Y Z) ≫
        (fun F G => limit.lift (F ⊗ G) { pt := limit F ⊗ limit G, π := NatTrans.mk fun j => limit.π F j ⊗ limit.π G j })
          X (Y ⊗ Z)

Next tactic:
ext j