l3lab/ntp-mathlib huggingface dataset:
/-- The currying functor, taking a functor `(C × D) ⥤ E` and producing a functor `C ⥤ (D ⥤ E)`.
-/
@[simps! obj_obj_obj obj_obj_map obj_map_app map_app_app]
def curry : (C × D ⥤ E) ⥤ C ⥤ D ⥤ E where
  obj F := curryObj F
  map T :=
    { app := fun X =>
        { app := fun Y => T.app (X, Y)
          naturality := fun Y Y' g => by
            dsimp [curryObj]
            

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
X✝ Y✝ : C × D ⥤ E
T : X✝ ⟶ Y✝
X : C
Y Y' : D
g : Y ⟶ Y'
⊢ X✝.map (𝟙 X, g) ≫ T.app (X, Y') = T.app (X, Y) ≫ Y✝.map (𝟙 X, g)

Next tactic:
rw [NatTrans.naturality]
/-- The currying functor, taking a functor `(C × D) ⥤ E` and producing a functor `C ⥤ (D ⥤ E)`.
-/
@[simps! obj_obj_obj obj_obj_map obj_map_app map_app_app]
def curry : (C × D ⥤ E) ⥤ C ⥤ D ⥤ E where
  obj F := curryObj F
  map T :=
    { app := fun X =>
        { app := fun Y => T.app (X, Y)
          naturality := fun Y Y' g => by
            dsimp [curryObj]
            rw [NatTrans.naturality] }
      naturality := fun X X' f => by
        

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
X✝ Y✝ : C × D ⥤ E
T : X✝ ⟶ Y✝
X X' : C
f : X ⟶ X'
⊢ ((fun F => curryObj F) X✝).map f ≫ (fun X => NatTrans.mk fun Y => T.app (X, Y)) X' =
    (fun X => NatTrans.mk fun Y => T.app (X, Y)) X ≫ ((fun F => curryObj F) Y✝).map f

Next tactic:
ext
/-- The currying functor, taking a functor `(C × D) ⥤ E` and producing a functor `C ⥤ (D ⥤ E)`.
-/
@[simps! obj_obj_obj obj_obj_map obj_map_app map_app_app]
def curry : (C × D ⥤ E) ⥤ C ⥤ D ⥤ E where
  obj F := curryObj F
  map T :=
    { app := fun X =>
        { app := fun Y => T.app (X, Y)
          naturality := fun Y Y' g => by
            dsimp [curryObj]
            rw [NatTrans.naturality] }
      naturality := fun X X' f => by
        ext; 

Proof state:
case w.h
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
X✝ Y✝ : C × D ⥤ E
T : X✝ ⟶ Y✝
X X' : C
f : X ⟶ X'
x✝ : D
⊢ (((fun F => curryObj F) X✝).map f ≫ (fun X => NatTrans.mk fun Y => T.app (X, Y)) X').app x✝ =
    ((fun X => NatTrans.mk fun Y => T.app (X, Y)) X ≫ ((fun F => curryObj F) Y✝).map f).app x✝

Next tactic:
dsimp [curryObj]
/-- The currying functor, taking a functor `(C × D) ⥤ E` and producing a functor `C ⥤ (D ⥤ E)`.
-/
@[simps! obj_obj_obj obj_obj_map obj_map_app map_app_app]
def curry : (C × D ⥤ E) ⥤ C ⥤ D ⥤ E where
  obj F := curryObj F
  map T :=
    { app := fun X =>
        { app := fun Y => T.app (X, Y)
          naturality := fun Y Y' g => by
            dsimp [curryObj]
            rw [NatTrans.naturality] }
      naturality := fun X X' f => by
        ext; dsimp [curryObj]
        

Proof state:
case w.h
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
X✝ Y✝ : C × D ⥤ E
T : X✝ ⟶ Y✝
X X' : C
f : X ⟶ X'
x✝ : D
⊢ X✝.map (f, 𝟙 x✝) ≫ T.app (X', x✝) = T.app (X, x✝) ≫ Y✝.map (f, 𝟙 x✝)

Next tactic:
rw [NatTrans.naturality]
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
X : C × D
⊢ ((curry ⋙ uncurry).obj F).obj X = ((𝟭 (C × D ⥤ E)).obj F).obj X

Next tactic:
simp
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
⊢ ∀ {X Y : C × D} (f : X ⟶ Y),
    ((curry ⋙ uncurry).obj F).map f ≫ ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) Y).hom =
      ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) X).hom ≫ ((𝟭 (C × D ⥤ E)).obj F).map f

Next tactic:
intros X Y f
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by intros X Y f; 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
X Y : C × D
f : X ⟶ Y
⊢ ((curry ⋙ uncurry).obj F).map f ≫ ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) Y).hom =
    ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) X).hom ≫ ((𝟭 (C × D ⥤ E)).obj F).map f

Next tactic:
cases X
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by intros X Y f; cases X; 

Proof state:
case mk
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
Y : C × D
fst✝ : C
snd✝ : D
f : (fst✝, snd✝) ⟶ Y
⊢ ((curry ⋙ uncurry).obj F).map f ≫ ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) Y).hom =
    ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) (fst✝, snd✝)).hom ≫ ((𝟭 (C × D ⥤ E)).obj F).map f

Next tactic:
cases Y
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by intros X Y f; cases X; cases Y; 

Proof state:
case mk.mk
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
fst✝¹ : C
snd✝¹ : D
fst✝ : C
snd✝ : D
f : (fst✝¹, snd✝¹) ⟶ (fst✝, snd✝)
⊢ ((curry ⋙ uncurry).obj F).map f ≫ ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) (fst✝, snd✝)).hom =
    ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) (fst✝¹, snd✝¹)).hom ≫ ((𝟭 (C × D ⥤ E)).obj F).map f

Next tactic:
cases f
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by intros X Y f; cases X; cases Y; cases f; 

Proof state:
case mk.mk.mk
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
fst✝² : C
snd✝² : D
fst✝¹ : C
snd✝¹ : D
fst✝ : (fst✝², snd✝²).1 ⟶ (fst✝¹, snd✝¹).1
snd✝ : (fst✝², snd✝²).2 ⟶ (fst✝¹, snd✝¹).2
⊢ ((curry ⋙ uncurry).obj F).map (fst✝, snd✝) ≫
      ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) (fst✝¹, snd✝¹)).hom =
    ((fun X => eqToIso (_ : F.obj (X.1, X.2) = F.obj X)) (fst✝², snd✝²)).hom ≫ ((𝟭 (C × D ⥤ E)).obj F).map (fst✝, snd✝)

Next tactic:
dsimp at *
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by intros X Y f; cases X; cases Y; cases f; dsimp at *; 

Proof state:
case mk.mk.mk
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
fst✝² : C
snd✝² : D
fst✝¹ : C
snd✝¹ : D
fst✝ : (fst✝², snd✝²).1 ⟶ (fst✝¹, snd✝¹).1
snd✝ : (fst✝², snd✝²).2 ⟶ (fst✝¹, snd✝¹).2
⊢ (F.map (fst✝, 𝟙 snd✝²) ≫ F.map (𝟙 fst✝¹, snd✝)) ≫ 𝟙 (F.obj (fst✝¹, snd✝¹)) =
    𝟙 (F.obj (fst✝², snd✝²)) ≫ F.map (fst✝, snd✝)

Next tactic:
rw [← F.map_comp]
/-- The equivalence of functor categories given by currying/uncurrying.
-/
@[simps!]
def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E :=
  Equivalence.mk uncurry curry
    (NatIso.ofComponents fun F =>
        NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _)
    (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp))
      (by intros X Y f; cases X; cases Y; cases f; dsimp at *; rw [← F.map_comp]; 

Proof state:
case mk.mk.mk
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : C × D ⥤ E
fst✝² : C
snd✝² : D
fst✝¹ : C
snd✝¹ : D
fst✝ : (fst✝², snd✝²).1 ⟶ (fst✝¹, snd✝¹).1
snd✝ : (fst✝², snd✝²).2 ⟶ (fst✝¹, snd✝¹).2
⊢ F.map ((fst✝, 𝟙 snd✝²) ≫ (𝟙 fst✝¹, snd✝)) ≫ 𝟙 (F.obj (fst✝¹, snd✝¹)) = 𝟙 (F.obj (fst✝², snd✝²)) ≫ F.map (fst✝, snd✝)

Next tactic:
simp
lemma uncurry_obj_curry_obj (F : B × C ⥤ D) : uncurry.obj (curry.obj F) = F :=
  Functor.ext (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : B × C ⥤ D
⊢ ∀ (X : B × C), (uncurry.obj (curry.obj F)).obj X = F.obj X

Next tactic:
simp
lemma uncurry_obj_curry_obj (F : B × C ⥤ D) : uncurry.obj (curry.obj F) = F :=
  Functor.ext (by simp) (fun ⟨x₁, x₂⟩ ⟨y₁, y₂⟩ ⟨f₁, f₂⟩ => by
    

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : B × C ⥤ D
x✝² x✝¹ : B × C
x₁ : B
x₂ : C
y₁ : B
y₂ : C
x✝ : (x₁, x₂) ⟶ (y₁, y₂)
f₁ : (x₁, x₂).1 ⟶ (y₁, y₂).1
f₂ : (x₁, x₂).2 ⟶ (y₁, y₂).2
⊢ (uncurry.obj (curry.obj F)).map (f₁, f₂) =
    eqToHom (_ : F.obj ((x₁, x₂).1, (x₁, x₂).2) = F.obj (x₁, x₂)) ≫
      F.map (f₁, f₂) ≫ eqToHom (_ : F.obj (y₁, y₂) = (uncurry.obj (curry.obj F)).obj (y₁, y₂))

Next tactic:
dsimp
lemma uncurry_obj_curry_obj (F : B × C ⥤ D) : uncurry.obj (curry.obj F) = F :=
  Functor.ext (by simp) (fun ⟨x₁, x₂⟩ ⟨y₁, y₂⟩ ⟨f₁, f₂⟩ => by
    dsimp
    

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : B × C ⥤ D
x✝² x✝¹ : B × C
x₁ : B
x₂ : C
y₁ : B
y₂ : C
x✝ : (x₁, x₂) ⟶ (y₁, y₂)
f₁ : (x₁, x₂).1 ⟶ (y₁, y₂).1
f₂ : (x₁, x₂).2 ⟶ (y₁, y₂).2
⊢ F.map (f₁, 𝟙 x₂) ≫ F.map (𝟙 y₁, f₂) = 𝟙 (F.obj (x₁, x₂)) ≫ F.map (f₁, f₂) ≫ 𝟙 (F.obj (y₁, y₂))

Next tactic:
simp only [← F.map_comp, Category.id_comp, Category.comp_id, prod_comp]
lemma curry_obj_injective {F₁ F₂ : C × D ⥤ E} (h : curry.obj F₁ = curry.obj F₂) :
    F₁ = F₂ := by
  

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ F₂ : C × D ⥤ E
h : curry.obj F₁ = curry.obj F₂
⊢ F₁ = F₂

Next tactic:
rw [← uncurry_obj_curry_obj F₁, ← uncurry_obj_curry_obj F₂, h]
lemma curry_obj_uncurry_obj (F : B ⥤ C ⥤ D) : curry.obj (uncurry.obj F) = F :=
  Functor.ext (fun _ => Functor.ext (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : B ⥤ C ⥤ D
x✝ : B
⊢ ∀ (X : C), ((curry.obj (uncurry.obj F)).obj x✝).obj X = (F.obj x✝).obj X

Next tactic:
simp
lemma curry_obj_uncurry_obj (F : B ⥤ C ⥤ D) : curry.obj (uncurry.obj F) = F :=
  Functor.ext (fun _ => Functor.ext (by simp) (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : B ⥤ C ⥤ D
x✝ : B
⊢ ∀ (X Y : C) (f : X ⟶ Y),
    ((curry.obj (uncurry.obj F)).obj x✝).map f =
      eqToHom (_ : (F.obj x✝).obj X = (F.obj x✝).obj X) ≫
        (F.obj x✝).map f ≫ eqToHom (_ : (F.obj x✝).obj Y = ((curry.obj (uncurry.obj F)).obj x✝).obj Y)

Next tactic:
simp
lemma curry_obj_uncurry_obj (F : B ⥤ C ⥤ D) : curry.obj (uncurry.obj F) = F :=
  Functor.ext (fun _ => Functor.ext (by simp) (by simp)) (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F : B ⥤ C ⥤ D
⊢ ∀ (X Y : B) (f : X ⟶ Y),
    (curry.obj (uncurry.obj F)).map f =
      eqToHom (_ : (curry.obj (uncurry.obj F)).obj X = F.obj X) ≫
        F.map f ≫ eqToHom (_ : F.obj Y = (curry.obj (uncurry.obj F)).obj Y)

Next tactic:
aesop_cat
lemma uncurry_obj_injective {F₁ F₂ : B ⥤ C ⥤ D} (h : uncurry.obj F₁ = uncurry.obj F₂) :
    F₁ = F₂ := by
  

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ F₂ : B ⥤ C ⥤ D
h : uncurry.obj F₁ = uncurry.obj F₂
⊢ F₁ = F₂

Next tactic:
rw [← curry_obj_uncurry_obj F₁, ← curry_obj_uncurry_obj F₂, h]
lemma flip_injective {F₁ F₂ : B ⥤ C ⥤ D} (h : F₁.flip = F₂.flip) :
    F₁ = F₂ := by
  

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ F₂ : B ⥤ C ⥤ D
h : Functor.flip F₁ = Functor.flip F₂
⊢ F₁ = F₂

Next tactic:
rw [← flip_flip F₁, ← flip_flip F₂, h]
lemma uncurry_obj_curry_obj_flip_flip (F₁ : B ⥤ C) (F₂ : D ⥤ E) (G : C × E ⥤ H) :
    uncurry.obj (F₂ ⋙ (F₁ ⋙ curry.obj G).flip).flip = (F₁.prod F₂) ⋙ G :=
  Functor.ext (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ : B ⥤ C
F₂ : D ⥤ E
G : C × E ⥤ H
⊢ ∀ (X : B × D), (uncurry.obj (Functor.flip (F₂ ⋙ Functor.flip (F₁ ⋙ curry.obj G)))).obj X = (prod F₁ F₂ ⋙ G).obj X

Next tactic:
simp
lemma uncurry_obj_curry_obj_flip_flip (F₁ : B ⥤ C) (F₂ : D ⥤ E) (G : C × E ⥤ H) :
    uncurry.obj (F₂ ⋙ (F₁ ⋙ curry.obj G).flip).flip = (F₁.prod F₂) ⋙ G :=
  Functor.ext (by simp) (fun ⟨x₁, x₂⟩ ⟨y₁, y₂⟩ ⟨f₁, f₂⟩ => by
    

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ : B ⥤ C
F₂ : D ⥤ E
G : C × E ⥤ H
x✝² x✝¹ : B × D
x₁ : B
x₂ : D
y₁ : B
y₂ : D
x✝ : (x₁, x₂) ⟶ (y₁, y₂)
f₁ : (x₁, x₂).1 ⟶ (y₁, y₂).1
f₂ : (x₁, x₂).2 ⟶ (y₁, y₂).2
⊢ (uncurry.obj (Functor.flip (F₂ ⋙ Functor.flip (F₁ ⋙ curry.obj G)))).map (f₁, f₂) =
    eqToHom (_ : G.obj (F₁.obj (x₁, x₂).1, F₂.obj (x₁, x₂).2) = G.obj (F₁.obj (x₁, x₂).1, F₂.obj (x₁, x₂).2)) ≫
      (prod F₁ F₂ ⋙ G).map (f₁, f₂) ≫
        eqToHom
          (_ :
            (prod F₁ F₂ ⋙ G).obj (y₁, y₂) =
              (uncurry.obj (Functor.flip (F₂ ⋙ Functor.flip (F₁ ⋙ curry.obj G)))).obj (y₁, y₂))

Next tactic:
dsimp
lemma uncurry_obj_curry_obj_flip_flip (F₁ : B ⥤ C) (F₂ : D ⥤ E) (G : C × E ⥤ H) :
    uncurry.obj (F₂ ⋙ (F₁ ⋙ curry.obj G).flip).flip = (F₁.prod F₂) ⋙ G :=
  Functor.ext (by simp) (fun ⟨x₁, x₂⟩ ⟨y₁, y₂⟩ ⟨f₁, f₂⟩ => by
    dsimp
    

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ : B ⥤ C
F₂ : D ⥤ E
G : C × E ⥤ H
x✝² x✝¹ : B × D
x₁ : B
x₂ : D
y₁ : B
y₂ : D
x✝ : (x₁, x₂) ⟶ (y₁, y₂)
f₁ : (x₁, x₂).1 ⟶ (y₁, y₂).1
f₂ : (x₁, x₂).2 ⟶ (y₁, y₂).2
⊢ G.map (F₁.map f₁, 𝟙 (F₂.obj x₂)) ≫ G.map (𝟙 (F₁.obj y₁), F₂.map f₂) =
    𝟙 (G.obj (F₁.obj x₁, F₂.obj x₂)) ≫ G.map (F₁.map f₁, F₂.map f₂) ≫ 𝟙 (G.obj (F₁.obj y₁, F₂.obj y₂))

Next tactic:
simp only [Category.id_comp, Category.comp_id, ← G.map_comp, prod_comp]
lemma uncurry_obj_curry_obj_flip_flip' (F₁ : B ⥤ C) (F₂ : D ⥤ E) (G : C × E ⥤ H) :
    uncurry.obj (F₁ ⋙ (F₂ ⋙ (curry.obj G).flip).flip) = (F₁.prod F₂) ⋙ G :=
  Functor.ext (by 

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ : B ⥤ C
F₂ : D ⥤ E
G : C × E ⥤ H
⊢ ∀ (X : B × D), (uncurry.obj (F₁ ⋙ Functor.flip (F₂ ⋙ Functor.flip (curry.obj G)))).obj X = (prod F₁ F₂ ⋙ G).obj X

Next tactic:
simp
lemma uncurry_obj_curry_obj_flip_flip' (F₁ : B ⥤ C) (F₂ : D ⥤ E) (G : C × E ⥤ H) :
    uncurry.obj (F₁ ⋙ (F₂ ⋙ (curry.obj G).flip).flip) = (F₁.prod F₂) ⋙ G :=
  Functor.ext (by simp) (fun ⟨x₁, x₂⟩ ⟨y₁, y₂⟩ ⟨f₁, f₂⟩ => by
    

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ : B ⥤ C
F₂ : D ⥤ E
G : C × E ⥤ H
x✝² x✝¹ : B × D
x₁ : B
x₂ : D
y₁ : B
y₂ : D
x✝ : (x₁, x₂) ⟶ (y₁, y₂)
f₁ : (x₁, x₂).1 ⟶ (y₁, y₂).1
f₂ : (x₁, x₂).2 ⟶ (y₁, y₂).2
⊢ (uncurry.obj (F₁ ⋙ Functor.flip (F₂ ⋙ Functor.flip (curry.obj G)))).map (f₁, f₂) =
    eqToHom (_ : G.obj (F₁.obj (x₁, x₂).1, F₂.obj (x₁, x₂).2) = G.obj (F₁.obj (x₁, x₂).1, F₂.obj (x₁, x₂).2)) ≫
      (prod F₁ F₂ ⋙ G).map (f₁, f₂) ≫
        eqToHom
          (_ :
            (prod F₁ F₂ ⋙ G).obj (y₁, y₂) =
              (uncurry.obj (F₁ ⋙ Functor.flip (F₂ ⋙ Functor.flip (curry.obj G)))).obj (y₁, y₂))

Next tactic:
dsimp
lemma uncurry_obj_curry_obj_flip_flip' (F₁ : B ⥤ C) (F₂ : D ⥤ E) (G : C × E ⥤ H) :
    uncurry.obj (F₁ ⋙ (F₂ ⋙ (curry.obj G).flip).flip) = (F₁.prod F₂) ⋙ G :=
  Functor.ext (by simp) (fun ⟨x₁, x₂⟩ ⟨y₁, y₂⟩ ⟨f₁, f₂⟩ => by
    dsimp
    

Proof state:
B : Type u₁
inst✝⁴ : Category.{v₁, u₁} B
C : Type u₂
inst✝³ : Category.{v₂, u₂} C
D : Type u₃
inst✝² : Category.{v₃, u₃} D
E : Type u₄
inst✝¹ : Category.{v₄, u₄} E
H : Type u₅
inst✝ : Category.{v₅, u₅} H
F₁ : B ⥤ C
F₂ : D ⥤ E
G : C × E ⥤ H
x✝² x✝¹ : B × D
x₁ : B
x₂ : D
y₁ : B
y₂ : D
x✝ : (x₁, x₂) ⟶ (y₁, y₂)
f₁ : (x₁, x₂).1 ⟶ (y₁, y₂).1
f₂ : (x₁, x₂).2 ⟶ (y₁, y₂).2
⊢ G.map (F₁.map f₁, 𝟙 (F₂.obj x₂)) ≫ G.map (𝟙 (F₁.obj y₁), F₂.map f₂) =
    𝟙 (G.obj (F₁.obj x₁, F₂.obj x₂)) ≫ G.map (F₁.map f₁, F₂.map f₂) ≫ 𝟙 (G.obj (F₁.obj y₁, F₂.obj y₂))

Next tactic:
simp only [Category.id_comp, Category.comp_id, ← G.map_comp, prod_comp]
@[reassoc]
theorem comp_δ_eq_zero {Y : C} {n : ℕ} {q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish q φ)
    (j : Fin (n + 2)) (hj₁ : j ≠ 0) (hj₂ : n + 2 ≤ (j : ℕ) + q) : φ ≫ X.δ j = 0 := by
  

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y : C
n q : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish q φ
j : Fin (n + 2)
hj₁ : j ≠ 0
hj₂ : n + 2 ≤ ↑j + q
⊢ φ ≫ δ X j = 0

Next tactic:
obtain ⟨i, rfl⟩ := Fin.eq_succ_of_ne_zero hj₁
@[reassoc]
theorem comp_δ_eq_zero {Y : C} {n : ℕ} {q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish q φ)
    (j : Fin (n + 2)) (hj₁ : j ≠ 0) (hj₂ : n + 2 ≤ (j : ℕ) + q) : φ ≫ X.δ j = 0 := by
  obtain ⟨i, rfl⟩ := Fin.eq_succ_of_ne_zero hj₁
  

Proof state:
case intro
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y : C
n q : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish q φ
i : Fin (n + 1)
hj₁ : Fin.succ i ≠ 0
hj₂ : n + 2 ≤ ↑(Fin.succ i) + q
⊢ φ ≫ δ X (Fin.succ i) = 0

Next tactic:
apply v i
@[reassoc]
theorem comp_δ_eq_zero {Y : C} {n : ℕ} {q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish q φ)
    (j : Fin (n + 2)) (hj₁ : j ≠ 0) (hj₂ : n + 2 ≤ (j : ℕ) + q) : φ ≫ X.δ j = 0 := by
  obtain ⟨i, rfl⟩ := Fin.eq_succ_of_ne_zero hj₁
  apply v i
  

Proof state:
case intro
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y : C
n q : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish q φ
i : Fin (n + 1)
hj₁ : Fin.succ i ≠ 0
hj₂ : n + 2 ≤ ↑(Fin.succ i) + q
⊢ n + 1 ≤ ↑i + q

Next tactic:
simp only [Fin.val_succ] at hj₂
@[reassoc]
theorem comp_δ_eq_zero {Y : C} {n : ℕ} {q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish q φ)
    (j : Fin (n + 2)) (hj₁ : j ≠ 0) (hj₂ : n + 2 ≤ (j : ℕ) + q) : φ ≫ X.δ j = 0 := by
  obtain ⟨i, rfl⟩ := Fin.eq_succ_of_ne_zero hj₁
  apply v i
  simp only [Fin.val_succ] at hj₂
  

Proof state:
case intro
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y : C
n q : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish q φ
i : Fin (n + 1)
hj₁ : Fin.succ i ≠ 0
hj₂ : n + 2 ≤ ↑i + 1 + q
⊢ n + 1 ≤ ↑i + q

Next tactic:
linarith
theorem of_succ {Y : C} {n q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish (q + 1) φ) :
    HigherFacesVanish q φ := fun j hj => v j (by 

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y : C
n q : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish (q + 1) φ
j : Fin (n + 1)
hj : n + 1 ≤ ↑j + q
⊢ n + 1 ≤ ↑j + (q + 1)

Next tactic:
simpa only [← add_assoc] using le_add_right hj
theorem of_comp {Y Z : C} {q n : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish q φ) (f : Z ⟶ Y) :
    HigherFacesVanish q (f ≫ φ) := fun j hj => by 

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y Z : C
q n : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish q φ
f : Z ⟶ Y
j : Fin (n + 1)
hj : n + 1 ≤ ↑j + q
⊢ (f ≫ φ) ≫ δ X (Fin.succ j) = 0

Next tactic:
rw [assoc, v j hj, comp_zero]
theorem comp_Hσ_eq {Y : C} {n a q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : HigherFacesVanish q φ)
    (hnaq : n = a + q) :
    φ ≫ (Hσ q).f (n + 1) =
      -φ ≫ X.δ ⟨a + 1, Nat.succ_lt_succ (Nat.lt_succ_iff.mpr (Nat.le.intro hnaq.symm))⟩ ≫
        X.σ ⟨a, Nat.lt_succ_iff.mpr (Nat.le.intro hnaq.symm)⟩ := by
  

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : Preadditive C
X : SimplicialObject C
Y : C
n a q : ℕ
φ : Y ⟶ X.obj (Opposite.op [n + 1])
v : HigherFacesVanish q φ
hnaq : n = a + q
⊢ φ ≫ HomologicalComplex.Hom.f (Hσ q) (n + 1) =
    -φ ≫
        δ X { val := a + 1, isLt := (_ : Nat.succ a < Nat.succ (n + 1)) } ≫
          σ X { val := a, isLt := (_ : a < Nat.succ n) }

Next tactic:
have hnaq_shift : ∀ d : ℕ, n + d = a + d + q := by
    intro d
    rw [add_assoc, add_comm d, ← add_assoc, hnaq]