l3lab/ntp-mathlib huggingface dataset:
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    

Proof state:
case h.right.right
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
u : ↑P { p // r p.1 p.2 }
xeq : (fun t => (↑t).1) <$> u = x
yeq : (fun t => (↑t).2) <$> u = y
a : P.A
f : B P a → { p // r p.1 p.2 }
h : u = { fst := a, snd := f }
⊢ ∀ (i : B P a), r (↑(f i)).1 (↑(f i)).2

Next tactic:
intro i
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    

Proof state:
case h.right.right
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
u : ↑P { p // r p.1 p.2 }
xeq : (fun t => (↑t).1) <$> u = x
yeq : (fun t => (↑t).2) <$> u = y
a : P.A
f : B P a → { p // r p.1 p.2 }
h : u = { fst := a, snd := f }
i : B P a
⊢ r (↑(f i)).1 (↑(f i)).2

Next tactic:
exact (f i).property
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  

Proof state:
case mpr
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
⊢ (∃ a f₀ f₁, x = { fst := a, snd := f₀ } ∧ y = { fst := a, snd := f₁ } ∧ ∀ (i : B P a), r (f₀ i) (f₁ i)) → Liftr r x y

Next tactic:
rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
  

Proof state:
case mpr.intro.intro.intro.intro.intro
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
a : P.A
f₀ f₁ : B P a → α
xeq : x = { fst := a, snd := f₀ }
yeq : y = { fst := a, snd := f₁ }
h : ∀ (i : B P a), r (f₀ i) (f₁ i)
⊢ Liftr r x y

Next tactic:
use ⟨a, fun i => ⟨(f₀ i, f₁ i), h i⟩⟩
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
  use ⟨a, fun i => ⟨(f₀ i, f₁ i), h i⟩⟩
  

Proof state:
case h
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
a : P.A
f₀ f₁ : B P a → α
xeq : x = { fst := a, snd := f₀ }
yeq : y = { fst := a, snd := f₁ }
h : ∀ (i : B P a), r (f₀ i) (f₁ i)
⊢ (fun t => (↑t).1) <$> { fst := a, snd := fun i => { val := (f₀ i, f₁ i), property := (_ : r (f₀ i) (f₁ i)) } } = x ∧
    (fun t => (↑t).2) <$> { fst := a, snd := fun i => { val := (f₀ i, f₁ i), property := (_ : r (f₀ i) (f₁ i)) } } = y

Next tactic:
constructor
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
  use ⟨a, fun i => ⟨(f₀ i, f₁ i), h i⟩⟩
  constructor
  · 

Proof state:
case h.left
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
a : P.A
f₀ f₁ : B P a → α
xeq : x = { fst := a, snd := f₀ }
yeq : y = { fst := a, snd := f₁ }
h : ∀ (i : B P a), r (f₀ i) (f₁ i)
⊢ (fun t => (↑t).1) <$> { fst := a, snd := fun i => { val := (f₀ i, f₁ i), property := (_ : r (f₀ i) (f₁ i)) } } = x

Next tactic:
rw [xeq]
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
  use ⟨a, fun i => ⟨(f₀ i, f₁ i), h i⟩⟩
  constructor
  · rw [xeq]
    

Proof state:
case h.left
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
a : P.A
f₀ f₁ : B P a → α
xeq : x = { fst := a, snd := f₀ }
yeq : y = { fst := a, snd := f₁ }
h : ∀ (i : B P a), r (f₀ i) (f₁ i)
⊢ (fun t => (↑t).1) <$> { fst := a, snd := fun i => { val := (f₀ i, f₁ i), property := (_ : r (f₀ i) (f₁ i)) } } =
    { fst := a, snd := f₀ }

Next tactic:
rfl
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
  use ⟨a, fun i => ⟨(f₀ i, f₁ i), h i⟩⟩
  constructor
  · rw [xeq]
    rfl
  

Proof state:
case h.right
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
a : P.A
f₀ f₁ : B P a → α
xeq : x = { fst := a, snd := f₀ }
yeq : y = { fst := a, snd := f₁ }
h : ∀ (i : B P a), r (f₀ i) (f₁ i)
⊢ (fun t => (↑t).2) <$> { fst := a, snd := fun i => { val := (f₀ i, f₁ i), property := (_ : r (f₀ i) (f₁ i)) } } = y

Next tactic:
rw [yeq]
theorem liftr_iff {α : Type u} (r : α → α → Prop) (x y : P α) :
    Liftr r x y ↔ ∃ a f₀ f₁, x = ⟨a, f₀⟩ ∧ y = ⟨a, f₁⟩ ∧ ∀ i, r (f₀ i) (f₁ i) := by
  constructor
  · rintro ⟨u, xeq, yeq⟩
    cases' h : u with a f
    use a, fun i => (f i).val.fst, fun i => (f i).val.snd
    constructor
    · rw [← xeq, h]
      rfl
    constructor
    · rw [← yeq, h]
      rfl
    intro i
    exact (f i).property
  rintro ⟨a, f₀, f₁, xeq, yeq, h⟩
  use ⟨a, fun i => ⟨(f₀ i, f₁ i), h i⟩⟩
  constructor
  · rw [xeq]
    rfl
  rw [yeq]; 

Proof state:
case h.right
P : PFunctor.{u}
α : Type u
r : α → α → Prop
x y : ↑P α
a : P.A
f₀ f₁ : B P a → α
xeq : x = { fst := a, snd := f₀ }
yeq : y = { fst := a, snd := f₁ }
h : ∀ (i : B P a), r (f₀ i) (f₁ i)
⊢ (fun t => (↑t).2) <$> { fst := a, snd := fun i => { val := (f₀ i, f₁ i), property := (_ : r (f₀ i) (f₁ i)) } } =
    { fst := a, snd := f₁ }

Next tactic:
rfl
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  

Proof state:
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
⊢ supp { fst := a, snd := f } = f '' univ

Next tactic:
ext x
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; 

Proof state:
case h
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
⊢ x ∈ supp { fst := a, snd := f } ↔ x ∈ f '' univ

Next tactic:
simp only [supp, image_univ, mem_range, mem_setOf_eq]
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  

Proof state:
case h
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
⊢ (∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x) ↔ ∃ y, f y = x

Next tactic:
constructor
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> 

Proof state:
case h.mp
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
⊢ (∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x) → ∃ y, f y = x

Next tactic:
intro h
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> 

Proof state:
case h.mpr
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
⊢ (∃ y, f y = x) → ∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x

Next tactic:
intro h
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · 

Proof state:
case h.mp
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
h : ∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x
⊢ ∃ y, f y = x

Next tactic:
apply @h fun x => ∃ y : P.B a, f y = x
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    

Proof state:
case h.mp
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
h : ∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x
⊢ Liftp (fun x => ∃ y, f y = x) { fst := a, snd := f }

Next tactic:
rw [liftp_iff']
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    rw [liftp_iff']
    

Proof state:
case h.mp
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
h : ∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x
⊢ ∀ (i : B P a), ∃ y, f y = f i

Next tactic:
intro
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    rw [liftp_iff']
    intro
    

Proof state:
case h.mp
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
h : ∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x
i✝ : B P a
⊢ ∃ y, f y = f i✝

Next tactic:
refine' ⟨_, rfl⟩
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    rw [liftp_iff']
    intro
    refine' ⟨_, rfl⟩
  · 

Proof state:
case h.mpr
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
h : ∃ y, f y = x
⊢ ∀ ⦃p : α → Prop⦄, Liftp p { fst := a, snd := f } → p x

Next tactic:
simp only [liftp_iff']
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    rw [liftp_iff']
    intro
    refine' ⟨_, rfl⟩
  · simp only [liftp_iff']
    

Proof state:
case h.mpr
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
h : ∃ y, f y = x
⊢ ∀ ⦃p : α → Prop⦄, (∀ (i : B P a), p (f i)) → p x

Next tactic:
cases h
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    rw [liftp_iff']
    intro
    refine' ⟨_, rfl⟩
  · simp only [liftp_iff']
    cases h
    

Proof state:
case h.mpr.intro
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
x : α
w✝ : B P a
h✝ : f w✝ = x
⊢ ∀ ⦃p : α → Prop⦄, (∀ (i : B P a), p (f i)) → p x

Next tactic:
subst x
theorem supp_eq {α : Type u} (a : P.A) (f : P.B a → α) :
    @supp.{u} P.Obj _ α (⟨a, f⟩ : P α) = f '' univ := by
  ext x; simp only [supp, image_univ, mem_range, mem_setOf_eq]
  constructor <;> intro h
  · apply @h fun x => ∃ y : P.B a, f y = x
    rw [liftp_iff']
    intro
    refine' ⟨_, rfl⟩
  · simp only [liftp_iff']
    cases h
    subst x
    

Proof state:
case h.mpr.intro
P : PFunctor.{u}
α : Type u
a : P.A
f : B P a → α
w✝ : B P a
⊢ ∀ ⦃p : α → Prop⦄, (∀ (i : B P a), p (f i)) → p (f w✝)

Next tactic:
tauto
lemma complex_exactAt_succ (n : ℕ) :
    P.complex.ExactAt (n + 1) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ ExactAt P.complex (n + 1)

Next tactic:
rw [← quasiIsoAt_iff_exactAt' P.π (n + 1) (exactAt_succ_single_obj _ _)]
lemma complex_exactAt_succ (n : ℕ) :
    P.complex.ExactAt (n + 1) := by
  rw [← quasiIsoAt_iff_exactAt' P.π (n + 1) (exactAt_succ_single_obj _ _)]
  · 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ QuasiIsoAt P.π (n + 1)

Next tactic:
infer_instance
lemma exact_succ (n : ℕ):
    (ShortComplex.mk _ _ (P.complex.d_comp_d (n + 2) (n + 1) n)).Exact :=
  ((HomologicalComplex.exactAt_iff' _ (n + 2) (n + 1) n) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ ComplexShape.prev (ComplexShape.down ℕ) (n + 1) = n + 2

Next tactic:
simp only [prev]
lemma exact_succ (n : ℕ):
    (ShortComplex.mk _ _ (P.complex.d_comp_d (n + 2) (n + 1) n)).Exact :=
  ((HomologicalComplex.exactAt_iff' _ (n + 2) (n + 1) n) (by simp only [prev]; 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ n + 1 + 1 = n + 2

Next tactic:
rfl
lemma exact_succ (n : ℕ):
    (ShortComplex.mk _ _ (P.complex.d_comp_d (n + 2) (n + 1) n)).Exact :=
  ((HomologicalComplex.exactAt_iff' _ (n + 2) (n + 1) n) (by simp only [prev]; rfl)
    (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ ComplexShape.next (ComplexShape.down ℕ) (n + 1) = n

Next tactic:
simp
@[simp]
theorem π_f_succ (n : ℕ) : P.π.f (n + 1) = 0 :=
  (isZero_single_obj_X _ _ _ _ (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ n + 1 ≠ 0

Next tactic:
simp
@[reassoc (attr := simp)]
theorem complex_d_comp_π_f_zero :
    P.complex.d 1 0 ≫ P.π.f 0 = 0 := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ HomologicalComplex.d P.complex 1 0 ≫ Hom.f P.π 0 = 0

Next tactic:
rw [← P.π.comm 1 0, single_obj_d, comp_zero]
theorem complex_d_succ_comp (n : ℕ) :
    P.complex.d n (n + 1) ≫ P.complex.d (n + 1) (n + 2) = 0 := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ HomologicalComplex.d P.complex n (n + 1) ≫ HomologicalComplex.d P.complex (n + 1) (n + 2) = 0

Next tactic:
simp
/-- `Z` is the cokernel of `P.complex.X 1 ⟶ P.complex.X 0` when `P : ProjectiveResolution Z`. -/
noncomputable def isColimitCokernelCofork : IsColimit (P.cokernelCofork) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ IsColimit (cokernelCofork P)

Next tactic:
refine IsColimit.ofIsoColimit (P.complex.opcyclesIsCokernel 1 0 (by simp)) ?_
/-- `Z` is the cokernel of `P.complex.X 1 ⟶ P.complex.X 0` when `P : ProjectiveResolution Z`. -/
noncomputable def isColimitCokernelCofork : IsColimit (P.cokernelCofork) := by
  refine IsColimit.ofIsoColimit (P.complex.opcyclesIsCokernel 1 0 (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ ComplexShape.prev (ComplexShape.down ℕ) 0 = 1

Next tactic:
simp
/-- `Z` is the cokernel of `P.complex.X 1 ⟶ P.complex.X 0` when `P : ProjectiveResolution Z`. -/
noncomputable def isColimitCokernelCofork : IsColimit (P.cokernelCofork) := by
  refine IsColimit.ofIsoColimit (P.complex.opcyclesIsCokernel 1 0 (by simp)) ?_
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ CokernelCofork.ofπ (pOpcycles P.complex 0) (_ : HomologicalComplex.d P.complex 1 0 ≫ pOpcycles P.complex 0 = 0) ≅
    cokernelCofork P

Next tactic:
refine Cofork.ext (P.complex.isoHomologyι₀.symm ≪≫ isoOfQuasiIsoAt P.π 0 ≪≫
    singleObjHomologySelfIso _ _ _) ?_
/-- `Z` is the cokernel of `P.complex.X 1 ⟶ P.complex.X 0` when `P : ProjectiveResolution Z`. -/
noncomputable def isColimitCokernelCofork : IsColimit (P.cokernelCofork) := by
  refine IsColimit.ofIsoColimit (P.complex.opcyclesIsCokernel 1 0 (by simp)) ?_
  refine Cofork.ext (P.complex.isoHomologyι₀.symm ≪≫ isoOfQuasiIsoAt P.π 0 ≪≫
    singleObjHomologySelfIso _ _ _) ?_
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ Cofork.π
        (CokernelCofork.ofπ (pOpcycles P.complex 0)
          (_ : HomologicalComplex.d P.complex 1 0 ≫ pOpcycles P.complex 0 = 0)) ≫
      ((isoHomologyι₀ P.complex).symm ≪≫
          isoOfQuasiIsoAt P.π 0 ≪≫ singleObjHomologySelfIso (ComplexShape.down ℕ) 0 Z).hom =
    Cofork.π (cokernelCofork P)

Next tactic:
rw [← cancel_mono (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 _).inv,
    ← cancel_mono (isoHomologyι₀ _).hom]
/-- `Z` is the cokernel of `P.complex.X 1 ⟶ P.complex.X 0` when `P : ProjectiveResolution Z`. -/
noncomputable def isColimitCokernelCofork : IsColimit (P.cokernelCofork) := by
  refine IsColimit.ofIsoColimit (P.complex.opcyclesIsCokernel 1 0 (by simp)) ?_
  refine Cofork.ext (P.complex.isoHomologyι₀.symm ≪≫ isoOfQuasiIsoAt P.π 0 ≪≫
    singleObjHomologySelfIso _ _ _) ?_
  rw [← cancel_mono (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 _).inv,
    ← cancel_mono (isoHomologyι₀ _).hom]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ ((Cofork.π
            (CokernelCofork.ofπ (pOpcycles P.complex 0)
              (_ : HomologicalComplex.d P.complex 1 0 ≫ pOpcycles P.complex 0 = 0)) ≫
          ((isoHomologyι₀ P.complex).symm ≪≫
              isoOfQuasiIsoAt P.π 0 ≪≫ singleObjHomologySelfIso (ComplexShape.down ℕ) 0 Z).hom) ≫
        (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 (cokernelCofork P).pt).inv) ≫
      (isoHomologyι₀ ((single C (ComplexShape.down ℕ) 0).obj (cokernelCofork P).pt)).hom =
    (Cofork.π (cokernelCofork P) ≫ (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 (cokernelCofork P).pt).inv) ≫
      (isoHomologyι₀ ((single C (ComplexShape.down ℕ) 0).obj (cokernelCofork P).pt)).hom

Next tactic:
dsimp
/-- `Z` is the cokernel of `P.complex.X 1 ⟶ P.complex.X 0` when `P : ProjectiveResolution Z`. -/
noncomputable def isColimitCokernelCofork : IsColimit (P.cokernelCofork) := by
  refine IsColimit.ofIsoColimit (P.complex.opcyclesIsCokernel 1 0 (by simp)) ?_
  refine Cofork.ext (P.complex.isoHomologyι₀.symm ≪≫ isoOfQuasiIsoAt P.π 0 ≪≫
    singleObjHomologySelfIso _ _ _) ?_
  rw [← cancel_mono (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 _).inv,
    ← cancel_mono (isoHomologyι₀ _).hom]
  dsimp
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ ((pOpcycles P.complex 0 ≫
          (isoHomologyι₀ P.complex).inv ≫
            homologyMap P.π 0 ≫ (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 Z).hom) ≫
        (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 Z).inv) ≫
      homologyι ((single C (ComplexShape.down ℕ) 0).obj Z) 0 =
    (Hom.f P.π 0 ≫ (singleObjHomologySelfIso (ComplexShape.down ℕ) 0 Z).inv) ≫
      homologyι ((single C (ComplexShape.down ℕ) 0).obj Z) 0

Next tactic:
simp only [isoHomologyι₀_inv_naturality_assoc, p_opcyclesMap_assoc, single₀_obj_zero, assoc,
    Iso.hom_inv_id, comp_id, isoHomologyι_inv_hom_id, singleObjHomologySelfIso_inv_homologyι,
    singleObjOpcyclesSelfIso_hom, single₀ObjXSelf, Iso.refl_inv, id_comp]
instance (n : ℕ) : Epi (P.π.f n) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n : ℕ
⊢ Epi (Hom.f P.π n)

Next tactic:
cases n
instance (n : ℕ) : Epi (P.π.f n) := by
  cases n
  · 

Proof state:
case zero
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
⊢ Epi (Hom.f P.π Nat.zero)

Next tactic:
exact epi_of_isColimit_cofork P.isColimitCokernelCofork
instance (n : ℕ) : Epi (P.π.f n) := by
  cases n
  · exact epi_of_isColimit_cofork P.isColimitCokernelCofork
  · 

Proof state:
case succ
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n✝ : ℕ
⊢ Epi (Hom.f P.π (Nat.succ n✝))

Next tactic:
rw [π_f_succ]
instance (n : ℕ) : Epi (P.π.f n) := by
  cases n
  · exact epi_of_isColimit_cofork P.isColimitCokernelCofork
  · rw [π_f_succ]; 

Proof state:
case succ
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : HasZeroObject C
inst✝ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
n✝ : ℕ
⊢ Epi 0

Next tactic:
infer_instance
/-- A projective object admits a trivial projective resolution: itself in degree 0. -/
@[simps]
noncomputable def self [Projective Z] : ProjectiveResolution Z where
  complex := (ChainComplex.single₀ C).obj Z
  π := 𝟙 ((ChainComplex.single₀ C).obj Z)
  projective n := by
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
inst✝ : Projective Z
n : ℕ
⊢ Projective (X ((single₀ C).obj Z) n)

Next tactic:
cases n
/-- A projective object admits a trivial projective resolution: itself in degree 0. -/
@[simps]
noncomputable def self [Projective Z] : ProjectiveResolution Z where
  complex := (ChainComplex.single₀ C).obj Z
  π := 𝟙 ((ChainComplex.single₀ C).obj Z)
  projective n := by
    cases n
    · 

Proof state:
case zero
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
inst✝ : Projective Z
⊢ Projective (X ((single₀ C).obj Z) Nat.zero)

Next tactic:
simpa
/-- A projective object admits a trivial projective resolution: itself in degree 0. -/
@[simps]
noncomputable def self [Projective Z] : ProjectiveResolution Z where
  complex := (ChainComplex.single₀ C).obj Z
  π := 𝟙 ((ChainComplex.single₀ C).obj Z)
  projective n := by
    cases n
    · simpa
    · 

Proof state:
case succ
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
inst✝ : Projective Z
n✝ : ℕ
⊢ Projective (X ((single₀ C).obj Z) (Nat.succ n✝))

Next tactic:
apply IsZero.projective
/-- A projective object admits a trivial projective resolution: itself in degree 0. -/
@[simps]
noncomputable def self [Projective Z] : ProjectiveResolution Z where
  complex := (ChainComplex.single₀ C).obj Z
  π := 𝟙 ((ChainComplex.single₀ C).obj Z)
  projective n := by
    cases n
    · simpa
    · apply IsZero.projective
      

Proof state:
case succ.h
C : Type u
inst✝³ : Category.{v, u} C
inst✝² : HasZeroObject C
inst✝¹ : HasZeroMorphisms C
Z : C
P : ProjectiveResolution Z
inst✝ : Projective Z
n✝ : ℕ
⊢ IsZero (X ((single₀ C).obj Z) (Nat.succ n✝))

Next tactic:
apply HomologicalComplex.isZero_single_obj_X