l3lab/ntp-mathlib huggingface dataset:
/-- If G preserves initial objects and pushouts, it preserves all finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesInitialAndPushouts [HasInitial C]
    [HasPushouts C] (G : C ⥤ D) [PreservesColimitsOfShape (Discrete.{0} PEmpty) G]
    [PreservesColimitsOfShape WalkingSpan G] : PreservesFiniteColimits G := by
  haveI : HasFiniteColimits C := hasFiniteColimits_of_hasInitial_and_pushouts
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
J : Type w
inst✝⁵ : SmallCategory J
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasInitial C
inst✝² : HasPushouts C
G : C ⥤ D
inst✝¹ : PreservesColimitsOfShape (Discrete PEmpty.{1}) G
inst✝ : PreservesColimitsOfShape WalkingSpan G
this : HasFiniteColimits C
⊢ PreservesFiniteColimits G

Next tactic:
haveI : PreservesColimitsOfShape (Discrete WalkingPair) G :=
    preservesBinaryCoproductsOfPreservesInitialAndPushouts G
/-- If G preserves initial objects and pushouts, it preserves all finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesInitialAndPushouts [HasInitial C]
    [HasPushouts C] (G : C ⥤ D) [PreservesColimitsOfShape (Discrete.{0} PEmpty) G]
    [PreservesColimitsOfShape WalkingSpan G] : PreservesFiniteColimits G := by
  haveI : HasFiniteColimits C := hasFiniteColimits_of_hasInitial_and_pushouts
  haveI : PreservesColimitsOfShape (Discrete WalkingPair) G :=
    preservesBinaryCoproductsOfPreservesInitialAndPushouts G
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
J : Type w
inst✝⁵ : SmallCategory J
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasInitial C
inst✝² : HasPushouts C
G : C ⥤ D
inst✝¹ : PreservesColimitsOfShape (Discrete PEmpty.{1}) G
inst✝ : PreservesColimitsOfShape WalkingSpan G
this✝ : HasFiniteColimits C
this : PreservesColimitsOfShape (Discrete WalkingPair) G
⊢ PreservesFiniteColimits G

Next tactic:
haveI : PreservesColimitsOfShape (WalkingParallelPair) G :=
      (preservesCoequalizersOfPreservesPushoutsAndBinaryCoproducts G)
/-- If G preserves initial objects and pushouts, it preserves all finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesInitialAndPushouts [HasInitial C]
    [HasPushouts C] (G : C ⥤ D) [PreservesColimitsOfShape (Discrete.{0} PEmpty) G]
    [PreservesColimitsOfShape WalkingSpan G] : PreservesFiniteColimits G := by
  haveI : HasFiniteColimits C := hasFiniteColimits_of_hasInitial_and_pushouts
  haveI : PreservesColimitsOfShape (Discrete WalkingPair) G :=
    preservesBinaryCoproductsOfPreservesInitialAndPushouts G
  haveI : PreservesColimitsOfShape (WalkingParallelPair) G :=
      (preservesCoequalizersOfPreservesPushoutsAndBinaryCoproducts G)
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
J : Type w
inst✝⁵ : SmallCategory J
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasInitial C
inst✝² : HasPushouts C
G : C ⥤ D
inst✝¹ : PreservesColimitsOfShape (Discrete PEmpty.{1}) G
inst✝ : PreservesColimitsOfShape WalkingSpan G
this✝¹ : HasFiniteColimits C
this✝ : PreservesColimitsOfShape (Discrete WalkingPair) G
this : PreservesColimitsOfShape WalkingParallelPair G
⊢ PreservesFiniteColimits G

Next tactic:
refine
    @preservesFiniteColimitsOfPreservesCoequalizersAndFiniteCoproducts _ _ _ _ _ _ G _ ?_
/-- If G preserves initial objects and pushouts, it preserves all finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesInitialAndPushouts [HasInitial C]
    [HasPushouts C] (G : C ⥤ D) [PreservesColimitsOfShape (Discrete.{0} PEmpty) G]
    [PreservesColimitsOfShape WalkingSpan G] : PreservesFiniteColimits G := by
  haveI : HasFiniteColimits C := hasFiniteColimits_of_hasInitial_and_pushouts
  haveI : PreservesColimitsOfShape (Discrete WalkingPair) G :=
    preservesBinaryCoproductsOfPreservesInitialAndPushouts G
  haveI : PreservesColimitsOfShape (WalkingParallelPair) G :=
      (preservesCoequalizersOfPreservesPushoutsAndBinaryCoproducts G)
  refine
    @preservesFiniteColimitsOfPreservesCoequalizersAndFiniteCoproducts _ _ _ _ _ _ G _ ?_
  

Proof state:
C : Type u
inst✝⁶ : Category.{v, u} C
J : Type w
inst✝⁵ : SmallCategory J
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasInitial C
inst✝² : HasPushouts C
G : C ⥤ D
inst✝¹ : PreservesColimitsOfShape (Discrete PEmpty.{1}) G
inst✝ : PreservesColimitsOfShape WalkingSpan G
this✝¹ : HasFiniteColimits C
this✝ : PreservesColimitsOfShape (Discrete WalkingPair) G
this : PreservesColimitsOfShape WalkingParallelPair G
⊢ PreservesFiniteCoproducts G

Next tactic:
apply PreservesFiniteCoproducts.mk
/-- If G preserves initial objects and pushouts, it preserves all finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesInitialAndPushouts [HasInitial C]
    [HasPushouts C] (G : C ⥤ D) [PreservesColimitsOfShape (Discrete.{0} PEmpty) G]
    [PreservesColimitsOfShape WalkingSpan G] : PreservesFiniteColimits G := by
  haveI : HasFiniteColimits C := hasFiniteColimits_of_hasInitial_and_pushouts
  haveI : PreservesColimitsOfShape (Discrete WalkingPair) G :=
    preservesBinaryCoproductsOfPreservesInitialAndPushouts G
  haveI : PreservesColimitsOfShape (WalkingParallelPair) G :=
      (preservesCoequalizersOfPreservesPushoutsAndBinaryCoproducts G)
  refine
    @preservesFiniteColimitsOfPreservesCoequalizersAndFiniteCoproducts _ _ _ _ _ _ G _ ?_
  apply PreservesFiniteCoproducts.mk
  

Proof state:
case preserves
C : Type u
inst✝⁶ : Category.{v, u} C
J : Type w
inst✝⁵ : SmallCategory J
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasInitial C
inst✝² : HasPushouts C
G : C ⥤ D
inst✝¹ : PreservesColimitsOfShape (Discrete PEmpty.{1}) G
inst✝ : PreservesColimitsOfShape WalkingSpan G
this✝¹ : HasFiniteColimits C
this✝ : PreservesColimitsOfShape (Discrete WalkingPair) G
this : PreservesColimitsOfShape WalkingParallelPair G
⊢ (J : Type) → [inst : Fintype J] → PreservesColimitsOfShape (Discrete J) G

Next tactic:
apply preservesFiniteCoproductsOfPreservesBinaryAndInitial G
theorem decide_True' (h : Decidable True) : decide True = true := by 

Proof state:
a b c d : Prop
p : ?m.25023
h : Decidable True
⊢ decide True = true

Next tactic:
simp
theorem decide_False' (h : Decidable False) : decide False = false := by 

Proof state:
a b c d : Prop
p : ?m.25090
h : Decidable False
⊢ decide False = false

Next tactic:
simp
def recOn_true [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u}
    (h₃ : p) (h₄ : h₁ h₃) : Decidable.recOn h h₂ h₁ :=
  cast (by 

Proof state:
a b c d p : Prop
h : Decidable p
h₁ : p → Sort u
h₂ : ¬p → Sort u
h₃ : p
h₄ : h₁ h₃
⊢ h₁ h₃ = Decidable.recOn h h₂ h₁

Next tactic:
match h with | .isTrue _ => rfl
def recOn_true [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u}
    (h₃ : p) (h₄ : h₁ h₃) : Decidable.recOn h h₂ h₁ :=
  cast (by match h with | .isTrue _ => 

Proof state:
a b c d p : Prop
h : Decidable p
h₁ : p → Sort u
h₂ : ¬p → Sort u
h₃ : p
h₄ : h₁ h₃
h✝ : p
⊢ h₁ h₃ = Decidable.recOn (isTrue h✝) h₂ h₁

Next tactic:
rfl
def recOn_false [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u} (h₃ : ¬p) (h₄ : h₂ h₃) :
    Decidable.recOn h h₂ h₁ :=
  cast (by 

Proof state:
a b c d p : Prop
h : Decidable p
h₁ : p → Sort u
h₂ : ¬p → Sort u
h₃ : ¬p
h₄ : h₂ h₃
⊢ h₂ h₃ = Decidable.recOn h h₂ h₁

Next tactic:
match h with | .isFalse _ => rfl
def recOn_false [h : Decidable p] {h₁ : p → Sort u} {h₂ : ¬p → Sort u} (h₃ : ¬p) (h₄ : h₂ h₃) :
    Decidable.recOn h h₂ h₁ :=
  cast (by match h with | .isFalse _ => 

Proof state:
a b c d p : Prop
h : Decidable p
h₁ : p → Sort u
h₂ : ¬p → Sort u
h₃ : ¬p
h₄ : h₂ h₃
h✝ : ¬p
⊢ h₂ h₃ = Decidable.recOn (isFalse h✝) h₂ h₁

Next tactic:
rfl
def decidableEq_of_bool_pred {α : Sort u} {p : α → α → Bool} (h₁ : IsDecEq p)
    (h₂ : IsDecRefl p) : DecidableEq α
  | x, y =>
    if hp : p x y = true then isTrue (h₁ hp)
    else isFalse (λ hxy : x = y => absurd (h₂ y) (by 

Proof state:
a b c d : Prop
p✝ : ?m.26618
α : Sort u
p : α → α → Bool
h₁ : IsDecEq p
h₂ : IsDecRefl p
x y : α
hp : ¬p x y = true
hxy : x = y
⊢ ¬p y y = true

Next tactic:
rwa [hxy] at hp
theorem let_value_heq {α : Sort v} {β : α → Sort u} {a₁ a₂ : α} (b : ∀ x : α, β x)
    (h : a₁ = a₂) : HEq (let x : α := a₁; b x) (let x : α := a₂; b x) := by 

Proof state:
a b✝ c d : Prop
p : ?m.29999
α : Sort v
β : α → Sort u
a₁ a₂ : α
b : (x : α) → β x
h : a₁ = a₂
⊢ HEq
    (let x := a₁;
    b x)
    (let x := a₂;
    b x)

Next tactic:
cases h
theorem let_value_heq {α : Sort v} {β : α → Sort u} {a₁ a₂ : α} (b : ∀ x : α, β x)
    (h : a₁ = a₂) : HEq (let x : α := a₁; b x) (let x : α := a₂; b x) := by cases h; 

Proof state:
case refl
a b✝ c d : Prop
p : ?m.29999
α : Sort v
β : α → Sort u
a₁ : α
b : (x : α) → β x
⊢ HEq
    (let x := a₁;
    b x)
    (let x := a₁;
    b x)

Next tactic:
rfl
theorem let_body_eq {α : Sort v} {β : α → Sort u} (a : α) {b₁ b₂ : ∀ x : α, β x}
    (h : ∀ x, b₁ x = b₂ x) : (let x : α := a; b₁ x) = (let x : α := a; b₂ x) := by 

Proof state:
a✝ b c d : Prop
p : ?m.30131
α : Sort v
β : α → Sort u
a : α
b₁ b₂ : (x : α) → β x
h : ∀ (x : α), b₁ x = b₂ x
⊢ (let x := a;
    b₁ x) =
    let x := a;
    b₂ x

Next tactic:
exact h _ ▸ rfl
theorem let_eq {α : Sort v} {β : Sort u} {a₁ a₂ : α} {b₁ b₂ : α → β}
    (h₁ : a₁ = a₂) (h₂ : ∀ x, b₁ x = b₂ x) :
    (let x : α := a₁; b₁ x) = (let x : α := a₂; b₂ x) := by 

Proof state:
a b c d : Prop
p : ?m.30205
α : Sort v
β : Sort u
a₁ a₂ : α
b₁ b₂ : α → β
h₁ : a₁ = a₂
h₂ : ∀ (x : α), b₁ x = b₂ x
⊢ (let x := a₁;
    b₁ x) =
    let x := a₂;
    b₂ x

Next tactic:
simp [h₁, h₂]
theorem of_iso {P Q : C} (i : P ≅ Q) (hP : Projective P) : Projective Q where
  factors f e e_epi :=
    let ⟨f', hf'⟩ := Projective.factors (i.hom ≫ f) e
    ⟨i.inv ≫ f', by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
P Q : C
i : P ≅ Q
hP : Projective P
E✝ X✝ : C
f : Q ⟶ X✝
e : E✝ ⟶ X✝
e_epi : Epi e
f' : P ⟶ E✝
hf' : f' ≫ e = i.hom ≫ f
⊢ (i.inv ≫ f') ≫ e = f

Next tactic:
simp [hf']
instance {P Q : C} [HasBinaryCoproduct P Q] [Projective P] [Projective Q] : Projective (P ⨿ Q) where
  factors f e epi := ⟨coprod.desc (factorThru (coprod.inl ≫ f) e) (factorThru (coprod.inr ≫ f) e),
    by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
P Q : C
inst✝² : HasBinaryCoproduct P Q
inst✝¹ : Projective P
inst✝ : Projective Q
E✝ X✝ : C
f : P ⨿ Q ⟶ X✝
e : E✝ ⟶ X✝
epi : Epi e
⊢ coprod.desc (factorThru (coprod.inl ≫ f) e) (factorThru (coprod.inr ≫ f) e) ≫ e = f

Next tactic:
aesop_cat
instance {β : Type v} (g : β → C) [HasCoproduct g] [∀ b, Projective (g b)] : Projective (∐ g) where
  factors f e epi := ⟨Sigma.desc fun b => factorThru (Sigma.ι g b ≫ f) e, by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
β : Type v
g : β → C
inst✝¹ : HasCoproduct g
inst✝ : ∀ (b : β), Projective (g b)
E✝ X✝ : C
f : ∐ g ⟶ X✝
e : E✝ ⟶ X✝
epi : Epi e
⊢ (Sigma.desc fun b => factorThru (Sigma.ι g b ≫ f) e) ≫ e = f

Next tactic:
aesop_cat
instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Projective P] [Projective Q] :
    Projective (P ⊞ Q) where
  factors f e epi := ⟨biprod.desc (factorThru (biprod.inl ≫ f) e) (factorThru (biprod.inr ≫ f) e),
    by 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
P Q : C
inst✝³ : HasZeroMorphisms C
inst✝² : HasBinaryBiproduct P Q
inst✝¹ : Projective P
inst✝ : Projective Q
E✝ X✝ : C
f : P ⊞ Q ⟶ X✝
e : E✝ ⟶ X✝
epi : Epi e
⊢ biprod.desc (factorThru (biprod.inl ≫ f) e) (factorThru (biprod.inr ≫ f) e) ≫ e = f

Next tactic:
aesop_cat
instance {β : Type v} (g : β → C) [HasZeroMorphisms C] [HasBiproduct g] [∀ b, Projective (g b)] :
    Projective (⨁ g) where
  factors f e epi := ⟨biproduct.desc fun b => factorThru (biproduct.ι g b ≫ f) e, by 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
β : Type v
g : β → C
inst✝² : HasZeroMorphisms C
inst✝¹ : HasBiproduct g
inst✝ : ∀ (b : β), Projective (g b)
E✝ X✝ : C
f : ⨁ g ⟶ X✝
e : E✝ ⟶ X✝
epi : Epi e
⊢ (biproduct.desc fun b => factorThru (biproduct.ι g b ≫ f) e) ≫ e = f

Next tactic:
aesop_cat
theorem map_projective (adj : F ⊣ G) [G.PreservesEpimorphisms] (P : C) (hP : Projective P) :
    Projective (F.obj P) where
  factors f g _ := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u'
inst✝¹ : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesEpimorphisms G
P : C
hP : Projective P
E✝ X✝ : D
f : F.obj P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
⊢ ∃ f', f' ≫ g = f

Next tactic:
rcases hP.factors (adj.unit.app P ≫ G.map f) (G.map g) with ⟨f', hf'⟩
theorem map_projective (adj : F ⊣ G) [G.PreservesEpimorphisms] (P : C) (hP : Projective P) :
    Projective (F.obj P) where
  factors f g _ := by
    rcases hP.factors (adj.unit.app P ≫ G.map f) (G.map g) with ⟨f', hf'⟩
    

Proof state:
case intro
C : Type u
inst✝² : Category.{v, u} C
D : Type u'
inst✝¹ : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesEpimorphisms G
P : C
hP : Projective P
E✝ X✝ : D
f : F.obj P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
f' : P ⟶ G.obj E✝
hf' : f' ≫ G.map g = adj.unit.app P ≫ G.map f
⊢ ∃ f', f' ≫ g = f

Next tactic:
use F.map f' ≫ adj.counit.app _
theorem map_projective (adj : F ⊣ G) [G.PreservesEpimorphisms] (P : C) (hP : Projective P) :
    Projective (F.obj P) where
  factors f g _ := by
    rcases hP.factors (adj.unit.app P ≫ G.map f) (G.map g) with ⟨f', hf'⟩
    use F.map f' ≫ adj.counit.app _
    

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
D : Type u'
inst✝¹ : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesEpimorphisms G
P : C
hP : Projective P
E✝ X✝ : D
f : F.obj P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
f' : P ⟶ G.obj E✝
hf' : f' ≫ G.map g = adj.unit.app P ≫ G.map f
⊢ (F.map f' ≫ adj.counit.app E✝) ≫ g = f

Next tactic:
rw [Category.assoc, ← Adjunction.counit_naturality, ← Category.assoc, ← F.map_comp, hf']
theorem map_projective (adj : F ⊣ G) [G.PreservesEpimorphisms] (P : C) (hP : Projective P) :
    Projective (F.obj P) where
  factors f g _ := by
    rcases hP.factors (adj.unit.app P ≫ G.map f) (G.map g) with ⟨f', hf'⟩
    use F.map f' ≫ adj.counit.app _
    rw [Category.assoc, ← Adjunction.counit_naturality, ← Category.assoc, ← F.map_comp, hf']
    

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
D : Type u'
inst✝¹ : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesEpimorphisms G
P : C
hP : Projective P
E✝ X✝ : D
f : F.obj P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
f' : P ⟶ G.obj E✝
hf' : f' ≫ G.map g = adj.unit.app P ≫ G.map f
⊢ F.map (adj.unit.app P ≫ G.map f) ≫ adj.counit.app X✝ = f

Next tactic:
simp
theorem projective_of_map_projective (adj : F ⊣ G) [Full F] [Faithful F] (P : C)
    (hP : Projective (F.obj P)) : Projective P where
  factors f g _ := by
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u'
inst✝² : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Full F
inst✝ : Faithful F
P : C
hP : Projective (F.obj P)
E✝ X✝ : C
f : P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
⊢ ∃ f', f' ≫ g = f

Next tactic:
haveI := Adjunction.leftAdjointPreservesColimits.{0, 0} adj
theorem projective_of_map_projective (adj : F ⊣ G) [Full F] [Faithful F] (P : C)
    (hP : Projective (F.obj P)) : Projective P where
  factors f g _ := by
    haveI := Adjunction.leftAdjointPreservesColimits.{0, 0} adj
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u'
inst✝² : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Full F
inst✝ : Faithful F
P : C
hP : Projective (F.obj P)
E✝ X✝ : C
f : P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
this : PreservesColimitsOfSize.{0, 0, v, v', u, u'} F
⊢ ∃ f', f' ≫ g = f

Next tactic:
rcases (@hP).1 (F.map f) (F.map g) with ⟨f', hf'⟩
theorem projective_of_map_projective (adj : F ⊣ G) [Full F] [Faithful F] (P : C)
    (hP : Projective (F.obj P)) : Projective P where
  factors f g _ := by
    haveI := Adjunction.leftAdjointPreservesColimits.{0, 0} adj
    rcases (@hP).1 (F.map f) (F.map g) with ⟨f', hf'⟩
    

Proof state:
case intro
C : Type u
inst✝³ : Category.{v, u} C
D : Type u'
inst✝² : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Full F
inst✝ : Faithful F
P : C
hP : Projective (F.obj P)
E✝ X✝ : C
f : P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
this : PreservesColimitsOfSize.{0, 0, v, v', u, u'} F
f' : F.obj P ⟶ F.obj E✝
hf' : f' ≫ F.map g = F.map f
⊢ ∃ f', f' ≫ g = f

Next tactic:
use adj.unit.app _ ≫ G.map f' ≫ (inv <| adj.unit.app _)
theorem projective_of_map_projective (adj : F ⊣ G) [Full F] [Faithful F] (P : C)
    (hP : Projective (F.obj P)) : Projective P where
  factors f g _ := by
    haveI := Adjunction.leftAdjointPreservesColimits.{0, 0} adj
    rcases (@hP).1 (F.map f) (F.map g) with ⟨f', hf'⟩
    use adj.unit.app _ ≫ G.map f' ≫ (inv <| adj.unit.app _)
    

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
D : Type u'
inst✝² : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Full F
inst✝ : Faithful F
P : C
hP : Projective (F.obj P)
E✝ X✝ : C
f : P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
this : PreservesColimitsOfSize.{0, 0, v, v', u, u'} F
f' : F.obj P ⟶ F.obj E✝
hf' : f' ≫ F.map g = F.map f
⊢ (adj.unit.app P ≫ G.map f' ≫ inv (adj.unit.app E✝)) ≫ g = f

Next tactic:
refine' Faithful.map_injective (F := F) _
theorem projective_of_map_projective (adj : F ⊣ G) [Full F] [Faithful F] (P : C)
    (hP : Projective (F.obj P)) : Projective P where
  factors f g _ := by
    haveI := Adjunction.leftAdjointPreservesColimits.{0, 0} adj
    rcases (@hP).1 (F.map f) (F.map g) with ⟨f', hf'⟩
    use adj.unit.app _ ≫ G.map f' ≫ (inv <| adj.unit.app _)
    refine' Faithful.map_injective (F := F) _
    

Proof state:
case h
C : Type u
inst✝³ : Category.{v, u} C
D : Type u'
inst✝² : Category.{v', u'} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Full F
inst✝ : Faithful F
P : C
hP : Projective (F.obj P)
E✝ X✝ : C
f : P ⟶ X✝
g : E✝ ⟶ X✝
x✝ : Epi g
this : PreservesColimitsOfSize.{0, 0, v, v', u, u'} F
f' : F.obj P ⟶ F.obj E✝
hf' : f' ≫ F.map g = F.map f
⊢ F.map ((adj.unit.app P ≫ G.map f' ≫ inv (adj.unit.app E✝)) ≫ g) = F.map f

Next tactic:
simpa
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
⊢ EnoughProjectives C ↔ EnoughProjectives D

Next tactic:
constructor
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  

Proof state:
case mp
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
⊢ EnoughProjectives C → EnoughProjectives D
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
⊢ EnoughProjectives D → EnoughProjectives C

Next tactic:
all_goals intro H; constructor; intro X; constructor
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals 

Proof state:
case mp
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
⊢ EnoughProjectives C → EnoughProjectives D

Next tactic:
intro H
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; 

Proof state:
case mp
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives C
⊢ EnoughProjectives D

Next tactic:
constructor
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; constructor; 

Proof state:
case mp.presentation
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives C
⊢ ∀ (X : D), Nonempty (ProjectivePresentation X)

Next tactic:
intro X
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; constructor; intro X; 

Proof state:
case mp.presentation
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives C
X : D
⊢ Nonempty (ProjectivePresentation X)

Next tactic:
constructor
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals 

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
⊢ EnoughProjectives D → EnoughProjectives C

Next tactic:
intro H
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; 

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives D
⊢ EnoughProjectives C

Next tactic:
constructor
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; constructor; 

Proof state:
case mpr.presentation
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives D
⊢ ∀ (X : C), Nonempty (ProjectivePresentation X)

Next tactic:
intro X
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; constructor; intro X; 

Proof state:
case mpr.presentation
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives D
X : C
⊢ Nonempty (ProjectivePresentation X)

Next tactic:
constructor
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; constructor; intro X; constructor
  · 

Proof state:
case mp.presentation.val
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives C
X : D
⊢ ProjectivePresentation X

Next tactic:
exact F.symm.projectivePresentationOfMapProjectivePresentation _
      (Nonempty.some (H.presentation (F.inverse.obj X)))
theorem enoughProjectives_iff (F : C ≌ D) : EnoughProjectives C ↔ EnoughProjectives D := by
  constructor
  all_goals intro H; constructor; intro X; constructor
  · exact F.symm.projectivePresentationOfMapProjectivePresentation _
      (Nonempty.some (H.presentation (F.inverse.obj X)))
  · 

Proof state:
case mpr.presentation.val
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ F : C ≌ D
H : EnoughProjectives D
X : C
⊢ ProjectivePresentation X

Next tactic:
exact F.projectivePresentationOfMapProjectivePresentation X
      (Nonempty.some (H.presentation (F.functor.obj X)))
@[simp]
theorem Exact.lift_comp {P Q R S : C} [Projective P] (h : P ⟶ R) (f : Q ⟶ R) (g : R ⟶ S)
    (hfg : Exact f g) (w : h ≫ g = 0) : Exact.lift h f g hfg w ≫ f = h := by
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : HasZeroMorphisms C
inst✝² : HasEqualizers C
inst✝¹ : HasImages C
P Q R S : C
inst✝ : Projective P
h : P ⟶ R
f : Q ⟶ R
g : R ⟶ S
hfg : Exact f g
w : h ≫ g = 0
⊢ lift h f g hfg w ≫ f = h

Next tactic:
simp only [Exact.lift]
@[simp]
theorem Exact.lift_comp {P Q R S : C} [Projective P] (h : P ⟶ R) (f : Q ⟶ R) (g : R ⟶ S)
    (hfg : Exact f g) (w : h ≫ g = 0) : Exact.lift h f g hfg w ≫ f = h := by
  simp only [Exact.lift]
  

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : HasZeroMorphisms C
inst✝² : HasEqualizers C
inst✝¹ : HasImages C
P Q R S : C
inst✝ : Projective P
h : P ⟶ R
f : Q ⟶ R
g : R ⟶ S
hfg : Exact f g
w : h ≫ g = 0
⊢ factorThru (factorThru (factorThruKernelSubobject g h w) (imageToKernel f g (_ : f ≫ g = 0)))
        (factorThruImageSubobject f) ≫
      f =
    h

Next tactic:
conv_lhs =>
    congr
    rfl
    rw [← imageSubobject_arrow_comp f]
@[simp]
theorem Exact.lift_comp {P Q R S : C} [Projective P] (h : P ⟶ R) (f : Q ⟶ R) (g : R ⟶ S)
    (hfg : Exact f g) (w : h ≫ g = 0) : Exact.lift h f g hfg w ≫ f = h := by
  simp only [Exact.lift]
  conv_lhs =>
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
inst✝³ : HasZeroMorphisms C
inst✝² : HasEqualizers C
inst✝¹ : HasImages C
P Q R S : C
inst✝ : Projective P
h : P ⟶ R
f : Q ⟶ R
g : R ⟶ S
hfg : Exact f g
w : h ≫ g = 0
| factorThru (factorThru (factorThruKernelSubobject g h w) (imageToKernel f g (_ : f ≫ g = 0)))
      (factorThruImageSubobject f) ≫
    f

Next tactic:
congr
    rfl
    rw [← imageSubobject_arrow_comp f]