l3lab/ntp-mathlib huggingface dataset:
/-- `(𝟙_ C ⟶ -)` is a lax monoidal functor to `Type`. -/
noncomputable
def coyonedaTensorUnit (C : Type u) [Category.{v} C] [MonoidalCategory C] :
    LaxMonoidalFunctor C (Type v) :=
  { coyoneda.obj (op (𝟙_ C)) with
    ε := fun _p => 𝟙 _
    μ := fun X Y p => (λ_ (𝟙_ C)).inv ≫ (p.1 ⊗ p.2)
    μ_natural := by aesop_cat
    associativity := fun X Y Z => by
      ext ⟨⟨f, g⟩, h⟩; dsimp at f g h
      dsimp; simp only [Iso.cancel_iso_inv_left, Category.assoc]
      conv_lhs =>
        rw [← Category.id_comp h, tensor_comp, Category.assoc, associator_naturality, ←
          Category.assoc, unitors_inv_equal, triangle_assoc_comp_right_inv]
      conv_rhs => rw [← Category.id_comp f, tensor_comp]
    left_unitality := by aesop_cat
    right_unitality := fun X => by
      ext ⟨f, ⟨⟩⟩; dsimp at f
      dsimp; 

Proof state:
case h.mk.unit
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : MonoidalCategory C
src✝ : C ⥤ Type v := coyoneda.obj (op (𝟙_ C))
X : C
f : 𝟙_ C ⟶ X
⊢ f = ((λ_ (𝟙_ C)).inv ≫ (f ⊗ 𝟙 (𝟙_ C))) ≫ (ρ_ X).hom

Next tactic:
simp only [Category.assoc]
/-- `(𝟙_ C ⟶ -)` is a lax monoidal functor to `Type`. -/
noncomputable
def coyonedaTensorUnit (C : Type u) [Category.{v} C] [MonoidalCategory C] :
    LaxMonoidalFunctor C (Type v) :=
  { coyoneda.obj (op (𝟙_ C)) with
    ε := fun _p => 𝟙 _
    μ := fun X Y p => (λ_ (𝟙_ C)).inv ≫ (p.1 ⊗ p.2)
    μ_natural := by aesop_cat
    associativity := fun X Y Z => by
      ext ⟨⟨f, g⟩, h⟩; dsimp at f g h
      dsimp; simp only [Iso.cancel_iso_inv_left, Category.assoc]
      conv_lhs =>
        rw [← Category.id_comp h, tensor_comp, Category.assoc, associator_naturality, ←
          Category.assoc, unitors_inv_equal, triangle_assoc_comp_right_inv]
      conv_rhs => rw [← Category.id_comp f, tensor_comp]
    left_unitality := by aesop_cat
    right_unitality := fun X => by
      ext ⟨f, ⟨⟩⟩; dsimp at f
      dsimp; simp only [Category.assoc]
      

Proof state:
case h.mk.unit
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : MonoidalCategory C
src✝ : C ⥤ Type v := coyoneda.obj (op (𝟙_ C))
X : C
f : 𝟙_ C ⟶ X
⊢ f = (λ_ (𝟙_ C)).inv ≫ (f ⊗ 𝟙 (𝟙_ C)) ≫ (ρ_ X).hom

Next tactic:
rw [rightUnitor_naturality, unitors_inv_equal, Iso.inv_hom_id_assoc]
/-- Auxiliary construction for `desc`. -/
def descFOne {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y) (J : InjectiveResolution Z) :
    J.cocomplex.X 1 ⟶ I.cocomplex.X 1 :=
  J.exact₀.descToInjective (descFZero f I J ≫ I.cocomplex.d 0 1)
    (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Z ⟶ Y
I : InjectiveResolution Y
J : InjectiveResolution Z
⊢ (ShortComplex.mk (HomologicalComplex.Hom.f J.ι 0) (HomologicalComplex.d J.cocomplex 0 1)
          (_ : HomologicalComplex.Hom.f J.ι 0 ≫ HomologicalComplex.d J.cocomplex 0 1 = 0)).f ≫
      descFZero f I J ≫ HomologicalComplex.d I.cocomplex 0 1 =
    0

Next tactic:
dsimp
/-- Auxiliary construction for `desc`. -/
def descFOne {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y) (J : InjectiveResolution Z) :
    J.cocomplex.X 1 ⟶ I.cocomplex.X 1 :=
  J.exact₀.descToInjective (descFZero f I J ≫ I.cocomplex.d 0 1)
    (by dsimp; 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Z ⟶ Y
I : InjectiveResolution Y
J : InjectiveResolution Z
⊢ HomologicalComplex.Hom.f J.ι 0 ≫ descFZero f I J ≫ HomologicalComplex.d I.cocomplex 0 1 = 0

Next tactic:
simp [← assoc, descFZero]
@[simp]
theorem descFOne_zero_comm {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y)
    (J : InjectiveResolution Z) :
    J.cocomplex.d 0 1 ≫ descFOne f I J = descFZero f I J ≫ I.cocomplex.d 0 1 := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Z ⟶ Y
I : InjectiveResolution Y
J : InjectiveResolution Z
⊢ HomologicalComplex.d J.cocomplex 0 1 ≫ descFOne f I J = descFZero f I J ≫ HomologicalComplex.d I.cocomplex 0 1

Next tactic:
apply J.exact₀.comp_descToInjective
/-- Auxiliary construction for `desc`. -/
def descFSucc {Y Z : C} (I : InjectiveResolution Y) (J : InjectiveResolution Z) (n : ℕ)
    (g : J.cocomplex.X n ⟶ I.cocomplex.X n) (g' : J.cocomplex.X (n + 1) ⟶ I.cocomplex.X (n + 1))
    (w : J.cocomplex.d n (n + 1) ≫ g' = g ≫ I.cocomplex.d n (n + 1)) :
    Σ'g'' : J.cocomplex.X (n + 2) ⟶ I.cocomplex.X (n + 2),
      J.cocomplex.d (n + 1) (n + 2) ≫ g'' = g' ≫ I.cocomplex.d (n + 1) (n + 2) :=
  ⟨(J.exact_succ n).descToInjective
    (g' ≫ I.cocomplex.d (n + 1) (n + 2)) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
n : ℕ
g : HomologicalComplex.X J.cocomplex n ⟶ HomologicalComplex.X I.cocomplex n
g' : HomologicalComplex.X J.cocomplex (n + 1) ⟶ HomologicalComplex.X I.cocomplex (n + 1)
w : HomologicalComplex.d J.cocomplex n (n + 1) ≫ g' = g ≫ HomologicalComplex.d I.cocomplex n (n + 1)
⊢ (ShortComplex.mk (HomologicalComplex.d J.cocomplex n (n + 1)) (HomologicalComplex.d J.cocomplex (n + 1) (n + 2))
          (_ : HomologicalComplex.d J.cocomplex n (n + 1) ≫ HomologicalComplex.d J.cocomplex (n + 1) (n + 2) = 0)).f ≫
      g' ≫ HomologicalComplex.d I.cocomplex (n + 1) (n + 2) =
    0

Next tactic:
simp [reassoc_of% w]
/-- The resolution maps intertwine the descent of a morphism and that morphism. -/
@[reassoc (attr := simp)]
theorem desc_commutes {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y)
    (J : InjectiveResolution Z) : J.ι ≫ desc f I J = (CochainComplex.single₀ C).map f ≫ I.ι := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Z ⟶ Y
I : InjectiveResolution Y
J : InjectiveResolution Z
⊢ J.ι ≫ desc f I J = (CochainComplex.single₀ C).map f ≫ I.ι

Next tactic:
ext
/-- The resolution maps intertwine the descent of a morphism and that morphism. -/
@[reassoc (attr := simp)]
theorem desc_commutes {Y Z : C} (f : Z ⟶ Y) (I : InjectiveResolution Y)
    (J : InjectiveResolution Z) : J.ι ≫ desc f I J = (CochainComplex.single₀ C).map f ≫ I.ι := by
  ext
  

Proof state:
case hfg
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Z ⟶ Y
I : InjectiveResolution Y
J : InjectiveResolution Z
⊢ HomologicalComplex.Hom.f (J.ι ≫ desc f I J) 0 = HomologicalComplex.Hom.f ((CochainComplex.single₀ C).map f ≫ I.ι) 0

Next tactic:
simp [desc, descFOne, descFZero]
@[reassoc (attr := simp)]
lemma desc_commutes_zero {Y Z : C} (f : Z ⟶ Y)
    (I : InjectiveResolution Y) (J : InjectiveResolution Z) :
    J.ι.f 0 ≫ (desc f I J).f 0 = f ≫ I.ι.f 0 :=
  (HomologicalComplex.congr_hom (desc_commutes f I J) 0).trans (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Z ⟶ Y
I : InjectiveResolution Y
J : InjectiveResolution Z
⊢ HomologicalComplex.Hom.f ((CochainComplex.single₀ C).map f ≫ I.ι) 0 = f ≫ HomologicalComplex.Hom.f I.ι 0

Next tactic:
simp
/-- An auxiliary definition for `descHomotopyZero`. -/
def descHomotopyZeroOne {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (comm : I.ι ≫ f = (0 : _ ⟶ J.cocomplex)) :
    I.cocomplex.X 2 ⟶ J.cocomplex.X 1 :=
  (I.exact_succ 0).descToInjective (f.f 1 - descHomotopyZeroZero f comm ≫ J.cocomplex.d 0 1)
    (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
comm : I.ι ≫ f = 0
⊢ (ShortComplex.mk (HomologicalComplex.d I.cocomplex 0 (0 + 1)) (HomologicalComplex.d I.cocomplex (0 + 1) (0 + 2))
          (_ : HomologicalComplex.d I.cocomplex 0 (0 + 1) ≫ HomologicalComplex.d I.cocomplex (0 + 1) (0 + 2) = 0)).f ≫
      (HomologicalComplex.Hom.f f 1 - descHomotopyZeroZero f comm ≫ HomologicalComplex.d J.cocomplex 0 1) =
    0

Next tactic:
rw [Preadditive.comp_sub, comp_descHomotopyZeroZero_assoc f comm,
          HomologicalComplex.Hom.comm, sub_self]
/-- An auxiliary definition for `descHomotopyZero`. -/
def descHomotopyZeroSucc {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (n : ℕ) (g : I.cocomplex.X (n + 1) ⟶ J.cocomplex.X n)
    (g' : I.cocomplex.X (n + 2) ⟶ J.cocomplex.X (n + 1))
    (w : f.f (n + 1) = I.cocomplex.d (n + 1) (n + 2) ≫ g' + g ≫ J.cocomplex.d n (n + 1)) :
    I.cocomplex.X (n + 3) ⟶ J.cocomplex.X (n + 2) :=
  (I.exact_succ (n + 1)).descToInjective (f.f (n + 2) - g' ≫ J.cocomplex.d _ _) (by
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
n : ℕ
g : HomologicalComplex.X I.cocomplex (n + 1) ⟶ HomologicalComplex.X J.cocomplex n
g' : HomologicalComplex.X I.cocomplex (n + 2) ⟶ HomologicalComplex.X J.cocomplex (n + 1)
w :
  HomologicalComplex.Hom.f f (n + 1) =
    HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ g' + g ≫ HomologicalComplex.d J.cocomplex n (n + 1)
⊢ (ShortComplex.mk (HomologicalComplex.d I.cocomplex (n + 1) (n + 1 + 1))
          (HomologicalComplex.d I.cocomplex (n + 1 + 1) (n + 1 + 2))
          (_ :
            HomologicalComplex.d I.cocomplex (n + 1) (n + 1 + 1) ≫
                HomologicalComplex.d I.cocomplex (n + 1 + 1) (n + 1 + 2) =
              0)).f ≫
      (HomologicalComplex.Hom.f f (n + 2) - g' ≫ HomologicalComplex.d J.cocomplex (n + 1) (n + 2)) =
    0

Next tactic:
dsimp
/-- An auxiliary definition for `descHomotopyZero`. -/
def descHomotopyZeroSucc {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (n : ℕ) (g : I.cocomplex.X (n + 1) ⟶ J.cocomplex.X n)
    (g' : I.cocomplex.X (n + 2) ⟶ J.cocomplex.X (n + 1))
    (w : f.f (n + 1) = I.cocomplex.d (n + 1) (n + 2) ≫ g' + g ≫ J.cocomplex.d n (n + 1)) :
    I.cocomplex.X (n + 3) ⟶ J.cocomplex.X (n + 2) :=
  (I.exact_succ (n + 1)).descToInjective (f.f (n + 2) - g' ≫ J.cocomplex.d _ _) (by
      dsimp
      

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
n : ℕ
g : HomologicalComplex.X I.cocomplex (n + 1) ⟶ HomologicalComplex.X J.cocomplex n
g' : HomologicalComplex.X I.cocomplex (n + 2) ⟶ HomologicalComplex.X J.cocomplex (n + 1)
w :
  HomologicalComplex.Hom.f f (n + 1) =
    HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ g' + g ≫ HomologicalComplex.d J.cocomplex n (n + 1)
⊢ HomologicalComplex.d I.cocomplex (n + 1) (n + 1 + 1) ≫
      (HomologicalComplex.Hom.f f (n + 2) - g' ≫ HomologicalComplex.d J.cocomplex (n + 1) (n + 2)) =
    0

Next tactic:
rw [Preadditive.comp_sub, ← HomologicalComplex.Hom.comm, w, Preadditive.add_comp,
        Category.assoc, Category.assoc, HomologicalComplex.d_comp_d, comp_zero,
        add_zero, sub_self]
/-- Any descent of the zero morphism is homotopic to zero. -/
def descHomotopyZero {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (comm : I.ι ≫ f = 0) : Homotopy f 0 :=
  Homotopy.mkCoinductive _ (descHomotopyZeroZero f comm) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
comm : I.ι ≫ f = 0
⊢ HomologicalComplex.Hom.f f 0 = HomologicalComplex.d I.cocomplex 0 1 ≫ descHomotopyZeroZero f comm

Next tactic:
simp
/-- Any descent of the zero morphism is homotopic to zero. -/
def descHomotopyZero {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (comm : I.ι ≫ f = 0) : Homotopy f 0 :=
  Homotopy.mkCoinductive _ (descHomotopyZeroZero f comm) (by simp)
    (descHomotopyZeroOne f comm) (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
comm : I.ι ≫ f = 0
⊢ HomologicalComplex.Hom.f f 1 =
    descHomotopyZeroZero f comm ≫ HomologicalComplex.d J.cocomplex 0 1 +
      HomologicalComplex.d I.cocomplex 1 2 ≫ descHomotopyZeroOne f comm

Next tactic:
simp
/-- Any descent of the zero morphism is homotopic to zero. -/
def descHomotopyZero {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (comm : I.ι ≫ f = 0) : Homotopy f 0 :=
  Homotopy.mkCoinductive _ (descHomotopyZeroZero f comm) (by simp)
    (descHomotopyZeroOne f comm) (by simp) (fun n ⟨g, g', w⟩ =>
    ⟨descHomotopyZeroSucc f n g g' (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
comm : I.ι ≫ f = 0
n : ℕ
x✝ :
  (f_1 : HomologicalComplex.X I.cocomplex (n + 1) ⟶ HomologicalComplex.X J.cocomplex n) ×'
    (f' : HomologicalComplex.X I.cocomplex (n + 2) ⟶ HomologicalComplex.X J.cocomplex (n + 1)) ×'
      HomologicalComplex.Hom.f f (n + 1) =
        f_1 ≫ HomologicalComplex.d J.cocomplex n (n + 1) + HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ f'
g : HomologicalComplex.X I.cocomplex (n + 1) ⟶ HomologicalComplex.X J.cocomplex n
g' : HomologicalComplex.X I.cocomplex (n + 2) ⟶ HomologicalComplex.X J.cocomplex (n + 1)
w :
  HomologicalComplex.Hom.f f (n + 1) =
    g ≫ HomologicalComplex.d J.cocomplex n (n + 1) + HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ g'
⊢ HomologicalComplex.Hom.f f (n + 1) =
    HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ g' + g ≫ HomologicalComplex.d J.cocomplex n (n + 1)

Next tactic:
simp only [w, add_comm]
/-- Any descent of the zero morphism is homotopic to zero. -/
def descHomotopyZero {Y Z : C} {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (f : I.cocomplex ⟶ J.cocomplex) (comm : I.ι ≫ f = 0) : Homotopy f 0 :=
  Homotopy.mkCoinductive _ (descHomotopyZeroZero f comm) (by simp)
    (descHomotopyZeroOne f comm) (by simp) (fun n ⟨g, g', w⟩ =>
    ⟨descHomotopyZeroSucc f n g g' (by simp only [w, add_comm]), by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
I : InjectiveResolution Y
J : InjectiveResolution Z
f : I.cocomplex ⟶ J.cocomplex
comm : I.ι ≫ f = 0
n : ℕ
x✝ :
  (f_1 : HomologicalComplex.X I.cocomplex (n + 1) ⟶ HomologicalComplex.X J.cocomplex n) ×'
    (f' : HomologicalComplex.X I.cocomplex (n + 2) ⟶ HomologicalComplex.X J.cocomplex (n + 1)) ×'
      HomologicalComplex.Hom.f f (n + 1) =
        f_1 ≫ HomologicalComplex.d J.cocomplex n (n + 1) + HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ f'
g : HomologicalComplex.X I.cocomplex (n + 1) ⟶ HomologicalComplex.X J.cocomplex n
g' : HomologicalComplex.X I.cocomplex (n + 2) ⟶ HomologicalComplex.X J.cocomplex (n + 1)
w :
  HomologicalComplex.Hom.f f (n + 1) =
    g ≫ HomologicalComplex.d J.cocomplex n (n + 1) + HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ g'
⊢ HomologicalComplex.Hom.f f (n + 2) =
    { fst := g, snd := { fst := g', snd := w } }.snd.fst ≫ HomologicalComplex.d J.cocomplex (n + 1) (n + 2) +
      HomologicalComplex.d I.cocomplex (n + 2) (n + 3) ≫
        descHomotopyZeroSucc f n g g'
          (_ :
            HomologicalComplex.Hom.f f (n + 1) =
              HomologicalComplex.d I.cocomplex (n + 1) (n + 2) ≫ g' + g ≫ HomologicalComplex.d J.cocomplex n (n + 1))

Next tactic:
simp
/-- Two descents of the same morphism are homotopic. -/
def descHomotopy {Y Z : C} (f : Y ⟶ Z) {I : InjectiveResolution Y} {J : InjectiveResolution Z}
    (g h : I.cocomplex ⟶ J.cocomplex) (g_comm : I.ι ≫ g = (CochainComplex.single₀ C).map f ≫ J.ι)
    (h_comm : I.ι ≫ h = (CochainComplex.single₀ C).map f ≫ J.ι) : Homotopy g h :=
  Homotopy.equivSubZero.invFun (descHomotopyZero _ (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
Y Z : C
f : Y ⟶ Z
I : InjectiveResolution Y
J : InjectiveResolution Z
g h : I.cocomplex ⟶ J.cocomplex
g_comm : I.ι ≫ g = (CochainComplex.single₀ C).map f ≫ J.ι
h_comm : I.ι ≫ h = (CochainComplex.single₀ C).map f ≫ J.ι
⊢ I.ι ≫ (g - h) = 0

Next tactic:
simp [g_comm, h_comm]
/-- The descent of the identity morphism is homotopic to the identity cochain map. -/
def descIdHomotopy (X : C) (I : InjectiveResolution X) :
    Homotopy (desc (𝟙 X) I I) (𝟙 I.cocomplex) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I : InjectiveResolution X
⊢ Homotopy (desc (𝟙 X) I I) (𝟙 I.cocomplex)

Next tactic:
apply descHomotopy (𝟙 X)
/-- The descent of the identity morphism is homotopic to the identity cochain map. -/
def descIdHomotopy (X : C) (I : InjectiveResolution X) :
    Homotopy (desc (𝟙 X) I I) (𝟙 I.cocomplex) := by
  apply descHomotopy (𝟙 X) <;> 

Proof state:
case g_comm
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I : InjectiveResolution X
⊢ I.ι ≫ desc (𝟙 X) I I = (CochainComplex.single₀ C).map (𝟙 X) ≫ I.ι

Next tactic:
simp
/-- The descent of the identity morphism is homotopic to the identity cochain map. -/
def descIdHomotopy (X : C) (I : InjectiveResolution X) :
    Homotopy (desc (𝟙 X) I I) (𝟙 I.cocomplex) := by
  apply descHomotopy (𝟙 X) <;> 

Proof state:
case h_comm
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I : InjectiveResolution X
⊢ I.ι ≫ 𝟙 I.cocomplex = (CochainComplex.single₀ C).map (𝟙 X) ≫ I.ι

Next tactic:
simp
/-- The descent of a composition is homotopic to the composition of the descents. -/
def descCompHomotopy {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) (I : InjectiveResolution X)
    (J : InjectiveResolution Y) (K : InjectiveResolution Z) :
    Homotopy (desc (f ≫ g) K I) (desc f J I ≫ desc g K J) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
I : InjectiveResolution X
J : InjectiveResolution Y
K : InjectiveResolution Z
⊢ Homotopy (desc (f ≫ g) K I) (desc f J I ≫ desc g K J)

Next tactic:
apply descHomotopy (f ≫ g)
/-- The descent of a composition is homotopic to the composition of the descents. -/
def descCompHomotopy {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) (I : InjectiveResolution X)
    (J : InjectiveResolution Y) (K : InjectiveResolution Z) :
    Homotopy (desc (f ≫ g) K I) (desc f J I ≫ desc g K J) := by
  apply descHomotopy (f ≫ g) <;> 

Proof state:
case g_comm
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
I : InjectiveResolution X
J : InjectiveResolution Y
K : InjectiveResolution Z
⊢ I.ι ≫ desc (f ≫ g) K I = (CochainComplex.single₀ C).map (f ≫ g) ≫ K.ι

Next tactic:
simp
/-- The descent of a composition is homotopic to the composition of the descents. -/
def descCompHomotopy {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) (I : InjectiveResolution X)
    (J : InjectiveResolution Y) (K : InjectiveResolution Z) :
    Homotopy (desc (f ≫ g) K I) (desc f J I ≫ desc g K J) := by
  apply descHomotopy (f ≫ g) <;> 

Proof state:
case h_comm
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X Y Z : C
f : X ⟶ Y
g : Y ⟶ Z
I : InjectiveResolution X
J : InjectiveResolution Y
K : InjectiveResolution Z
⊢ I.ι ≫ desc f J I ≫ desc g K J = (CochainComplex.single₀ C).map (f ≫ g) ≫ K.ι

Next tactic:
simp
/-- Any two injective resolutions are homotopy equivalent. -/
def homotopyEquiv {X : C} (I J : InjectiveResolution X) :
    HomotopyEquiv I.cocomplex J.cocomplex where
  hom := desc (𝟙 X) J I
  inv := desc (𝟙 X) I J
  homotopyHomInvId := (descCompHomotopy (𝟙 X) (𝟙 X) I J I).symm.trans <| by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I J : InjectiveResolution X
⊢ Homotopy (desc (𝟙 X ≫ 𝟙 X) I I) (𝟙 I.cocomplex)

Next tactic:
simpa [id_comp] using descIdHomotopy _ _
/-- Any two injective resolutions are homotopy equivalent. -/
def homotopyEquiv {X : C} (I J : InjectiveResolution X) :
    HomotopyEquiv I.cocomplex J.cocomplex where
  hom := desc (𝟙 X) J I
  inv := desc (𝟙 X) I J
  homotopyHomInvId := (descCompHomotopy (𝟙 X) (𝟙 X) I J I).symm.trans <| by
    simpa [id_comp] using descIdHomotopy _ _
  homotopyInvHomId := (descCompHomotopy (𝟙 X) (𝟙 X) J I J).symm.trans <| by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I J : InjectiveResolution X
⊢ Homotopy (desc (𝟙 X ≫ 𝟙 X) J J) (𝟙 J.cocomplex)

Next tactic:
simpa [id_comp] using descIdHomotopy _ _
@[reassoc (attr := simp)] -- Porting note: Originally `@[simp, reassoc.1]`
theorem homotopyEquiv_hom_ι {X : C} (I J : InjectiveResolution X) :
    I.ι ≫ (homotopyEquiv I J).hom = J.ι := by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I J : InjectiveResolution X
⊢ I.ι ≫ (homotopyEquiv I J).hom = J.ι

Next tactic:
simp [homotopyEquiv]
@[reassoc (attr := simp)] -- Porting note: Originally `@[simp, reassoc.1]`
theorem homotopyEquiv_inv_ι {X : C} (I J : InjectiveResolution X) :
    J.ι ≫ (homotopyEquiv I J).inv = I.ι := by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : Abelian C
X : C
I J : InjectiveResolution X
⊢ J.ι ≫ (homotopyEquiv I J).inv = I.ι

Next tactic:
simp [homotopyEquiv]
/-- Taking injective resolutions is functorial,
if considered with target the homotopy category
(`ℕ`-indexed cochain complexes and chain maps up to homotopy).
-/
def injectiveResolutions : C ⥤ HomotopyCategory C (ComplexShape.up ℕ) where
  obj X := (HomotopyCategory.quotient _ _).obj (injectiveResolution X).cocomplex
  map f := (HomotopyCategory.quotient _ _).map (InjectiveResolution.desc f _ _)
  map_id X := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Abelian C
inst✝ : HasInjectiveResolutions C
X : C
⊢ { obj := fun X => (HomotopyCategory.quotient C (ComplexShape.up ℕ)).obj (injectiveResolution X).cocomplex,
          map := fun {X Y} f =>
            (HomotopyCategory.quotient C (ComplexShape.up ℕ)).map
              (InjectiveResolution.desc f (injectiveResolution Y) (injectiveResolution X)) }.map
      (𝟙 X) =
    𝟙
      ({ obj := fun X => (HomotopyCategory.quotient C (ComplexShape.up ℕ)).obj (injectiveResolution X).cocomplex,
            map := fun {X Y} f =>
              (HomotopyCategory.quotient C (ComplexShape.up ℕ)).map
                (InjectiveResolution.desc f (injectiveResolution Y) (injectiveResolution X)) }.obj
        X)

Next tactic:
rw [← (HomotopyCategory.quotient _ _).map_id]
/-- Taking injective resolutions is functorial,
if considered with target the homotopy category
(`ℕ`-indexed cochain complexes and chain maps up to homotopy).
-/
def injectiveResolutions : C ⥤ HomotopyCategory C (ComplexShape.up ℕ) where
  obj X := (HomotopyCategory.quotient _ _).obj (injectiveResolution X).cocomplex
  map f := (HomotopyCategory.quotient _ _).map (InjectiveResolution.desc f _ _)
  map_id X := by
    rw [← (HomotopyCategory.quotient _ _).map_id]
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Abelian C
inst✝ : HasInjectiveResolutions C
X : C
⊢ { obj := fun X => (HomotopyCategory.quotient C (ComplexShape.up ℕ)).obj (injectiveResolution X).cocomplex,
          map := fun {X Y} f =>
            (HomotopyCategory.quotient C (ComplexShape.up ℕ)).map
              (InjectiveResolution.desc f (injectiveResolution Y) (injectiveResolution X)) }.map
      (𝟙 X) =
    (HomotopyCategory.quotient C (ComplexShape.up ℕ)).map (𝟙 (injectiveResolution X).cocomplex)

Next tactic:
apply HomotopyCategory.eq_of_homotopy
/-- Taking injective resolutions is functorial,
if considered with target the homotopy category
(`ℕ`-indexed cochain complexes and chain maps up to homotopy).
-/
def injectiveResolutions : C ⥤ HomotopyCategory C (ComplexShape.up ℕ) where
  obj X := (HomotopyCategory.quotient _ _).obj (injectiveResolution X).cocomplex
  map f := (HomotopyCategory.quotient _ _).map (InjectiveResolution.desc f _ _)
  map_id X := by
    rw [← (HomotopyCategory.quotient _ _).map_id]
    apply HomotopyCategory.eq_of_homotopy
    

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Abelian C
inst✝ : HasInjectiveResolutions C
X : C
⊢ Homotopy (InjectiveResolution.desc (𝟙 X) (injectiveResolution X) (injectiveResolution X))
    (𝟙 (injectiveResolution X).cocomplex)

Next tactic:
apply InjectiveResolution.descIdHomotopy