l3lab/ntp-mathlib huggingface dataset:
instance {P Q : C} [HasBinaryProduct P Q] [Injective P] [Injective Q] : Injective (P ⨯ Q) where
  factors g f mono := by
    skip
    use Limits.prod.lift (factorThru (g ≫ Limits.prod.fst) f) (factorThru (g ≫ Limits.prod.snd) f)
    simp only [prod.comp_lift, comp_factorThru]
    ext
    · simp only [prod.lift_fst]
    · 

Proof state:
case h.h₂
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
P Q : C
inst✝² : HasBinaryProduct P Q
inst✝¹ : Injective P
inst✝ : Injective Q
X✝ Y✝ : C
g : X✝ ⟶ P ⨯ Q
f : X✝ ⟶ Y✝
mono : Mono f
⊢ prod.lift (g ≫ prod.fst) (g ≫ prod.snd) ≫ prod.snd = g ≫ prod.snd

Next tactic:
simp only [prod.lift_snd]
instance {β : Type v} (c : β → C) [HasProduct c] [∀ b, Injective (c b)] : Injective (∏ c) where
  factors g f mono := by
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝¹ : HasProduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ∏ c
f : X✝ ⟶ Y✝
mono : Mono f
⊢ ∃ h, f ≫ h = g

Next tactic:
skip
instance {β : Type v} (c : β → C) [HasProduct c] [∀ b, Injective (c b)] : Injective (∏ c) where
  factors g f mono := by
    skip
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝¹ : HasProduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ∏ c
f : X✝ ⟶ Y✝
mono : Mono f
⊢ ∃ h, f ≫ h = g

Next tactic:
refine' ⟨Pi.lift fun b => factorThru (g ≫ Pi.π c _) f, _⟩
instance {β : Type v} (c : β → C) [HasProduct c] [∀ b, Injective (c b)] : Injective (∏ c) where
  factors g f mono := by
    skip
    refine' ⟨Pi.lift fun b => factorThru (g ≫ Pi.π c _) f, _⟩
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝¹ : HasProduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ∏ c
f : X✝ ⟶ Y✝
mono : Mono f
⊢ (f ≫ Pi.lift fun b => factorThru (g ≫ Pi.π c b) f) = g

Next tactic:
ext b
instance {β : Type v} (c : β → C) [HasProduct c] [∀ b, Injective (c b)] : Injective (∏ c) where
  factors g f mono := by
    skip
    refine' ⟨Pi.lift fun b => factorThru (g ≫ Pi.π c _) f, _⟩
    ext b
    

Proof state:
case h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝¹ : HasProduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ∏ c
f : X✝ ⟶ Y✝
mono : Mono f
b : β
⊢ (f ≫ Pi.lift fun b => factorThru (g ≫ Pi.π c b) f) ≫ Pi.π c b = g ≫ Pi.π c b

Next tactic:
simp only [Category.assoc, limit.lift_π, Fan.mk_π_app, comp_factorThru]
instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Injective P] [Injective Q] :
    Injective (P ⊞ Q) where
  factors g f mono := by
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
P Q : C
inst✝³ : HasZeroMorphisms C
inst✝² : HasBinaryBiproduct P Q
inst✝¹ : Injective P
inst✝ : Injective Q
X✝ Y✝ : C
g : X✝ ⟶ P ⊞ Q
f : X✝ ⟶ Y✝
mono : Mono f
⊢ ∃ h, f ≫ h = g

Next tactic:
skip
instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Injective P] [Injective Q] :
    Injective (P ⊞ Q) where
  factors g f mono := by
    skip
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
P Q : C
inst✝³ : HasZeroMorphisms C
inst✝² : HasBinaryBiproduct P Q
inst✝¹ : Injective P
inst✝ : Injective Q
X✝ Y✝ : C
g : X✝ ⟶ P ⊞ Q
f : X✝ ⟶ Y✝
mono : Mono f
⊢ ∃ h, f ≫ h = g

Next tactic:
refine' ⟨biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f), _⟩
instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Injective P] [Injective Q] :
    Injective (P ⊞ Q) where
  factors g f mono := by
    skip
    refine' ⟨biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f), _⟩
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
P Q : C
inst✝³ : HasZeroMorphisms C
inst✝² : HasBinaryBiproduct P Q
inst✝¹ : Injective P
inst✝ : Injective Q
X✝ Y✝ : C
g : X✝ ⟶ P ⊞ Q
f : X✝ ⟶ Y✝
mono : Mono f
⊢ f ≫ biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f) = g

Next tactic:
ext
instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Injective P] [Injective Q] :
    Injective (P ⊞ Q) where
  factors g f mono := by
    skip
    refine' ⟨biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f), _⟩
    ext
    · 

Proof state:
case h₀
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
P Q : C
inst✝³ : HasZeroMorphisms C
inst✝² : HasBinaryBiproduct P Q
inst✝¹ : Injective P
inst✝ : Injective Q
X✝ Y✝ : C
g : X✝ ⟶ P ⊞ Q
f : X✝ ⟶ Y✝
mono : Mono f
⊢ (f ≫ biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f)) ≫ biprod.fst = g ≫ biprod.fst

Next tactic:
simp only [Category.assoc, biprod.lift_fst, comp_factorThru]
instance {P Q : C} [HasZeroMorphisms C] [HasBinaryBiproduct P Q] [Injective P] [Injective Q] :
    Injective (P ⊞ Q) where
  factors g f mono := by
    skip
    refine' ⟨biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f), _⟩
    ext
    · simp only [Category.assoc, biprod.lift_fst, comp_factorThru]
    · 

Proof state:
case h₁
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
P Q : C
inst✝³ : HasZeroMorphisms C
inst✝² : HasBinaryBiproduct P Q
inst✝¹ : Injective P
inst✝ : Injective Q
X✝ Y✝ : C
g : X✝ ⟶ P ⊞ Q
f : X✝ ⟶ Y✝
mono : Mono f
⊢ (f ≫ biprod.lift (factorThru (g ≫ biprod.fst) f) (factorThru (g ≫ biprod.snd) f)) ≫ biprod.snd = g ≫ biprod.snd

Next tactic:
simp only [Category.assoc, biprod.lift_snd, comp_factorThru]
instance {β : Type v} (c : β → C) [HasZeroMorphisms C] [HasBiproduct c] [∀ b, Injective (c b)] :
    Injective (⨁ c) where
  factors g f mono := by
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝² : HasZeroMorphisms C
inst✝¹ : HasBiproduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ⨁ c
f : X✝ ⟶ Y✝
mono : Mono f
⊢ ∃ h, f ≫ h = g

Next tactic:
skip
instance {β : Type v} (c : β → C) [HasZeroMorphisms C] [HasBiproduct c] [∀ b, Injective (c b)] :
    Injective (⨁ c) where
  factors g f mono := by
    skip
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝² : HasZeroMorphisms C
inst✝¹ : HasBiproduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ⨁ c
f : X✝ ⟶ Y✝
mono : Mono f
⊢ ∃ h, f ≫ h = g

Next tactic:
refine' ⟨biproduct.lift fun b => factorThru (g ≫ biproduct.π _ _) f, _⟩
instance {β : Type v} (c : β → C) [HasZeroMorphisms C] [HasBiproduct c] [∀ b, Injective (c b)] :
    Injective (⨁ c) where
  factors g f mono := by
    skip
    refine' ⟨biproduct.lift fun b => factorThru (g ≫ biproduct.π _ _) f, _⟩
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝² : HasZeroMorphisms C
inst✝¹ : HasBiproduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ⨁ c
f : X✝ ⟶ Y✝
mono : Mono f
⊢ (f ≫ biproduct.lift fun b => factorThru (g ≫ biproduct.π c b) f) = g

Next tactic:
ext
instance {β : Type v} (c : β → C) [HasZeroMorphisms C] [HasBiproduct c] [∀ b, Injective (c b)] :
    Injective (⨁ c) where
  factors g f mono := by
    skip
    refine' ⟨biproduct.lift fun b => factorThru (g ≫ biproduct.π _ _) f, _⟩
    ext
    

Proof state:
case w
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
β : Type v
c : β → C
inst✝² : HasZeroMorphisms C
inst✝¹ : HasBiproduct c
inst✝ : ∀ (b : β), Injective (c b)
X✝ Y✝ : C
g : X✝ ⟶ ⨁ c
f : X✝ ⟶ Y✝
mono : Mono f
j✝ : β
⊢ (f ≫ biproduct.lift fun b => factorThru (g ≫ biproduct.π c b) f) ≫ biproduct.π c j✝ = g ≫ biproduct.π c j✝

Next tactic:
simp only [Category.assoc, biproduct.lift_π, comp_factorThru]
instance {P : Cᵒᵖ} [Projective P] : Injective (unop P) where
  factors g f mono :=
    ⟨(@Projective.factorThru Cᵒᵖ _ P _ _ _ g.op f.op _).unop, Quiver.Hom.op_inj (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P : Cᵒᵖ
inst✝ : Projective P
X✝ Y✝ : C
g : X✝ ⟶ P.unop
f : X✝ ⟶ Y✝
mono : Mono f
⊢ (f ≫ (Projective.factorThru g.op f.op).unop).op = g.op

Next tactic:
simp
instance {J : Cᵒᵖ} [Injective J] : Projective (unop J) where
  factors f e he :=
    ⟨(@factorThru Cᵒᵖ _ J _ _ _ f.op e.op _).unop, Quiver.Hom.op_inj (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : Cᵒᵖ
inst✝ : Injective J
E✝ X✝ : C
f : J.unop ⟶ X✝
e : E✝ ⟶ X✝
he : Epi e
⊢ ((factorThru f.op e.op).unop ≫ e).op = f.op

Next tactic:
simp
instance {J : C} [Injective J] : Projective (op J) where
  factors f e epi :=
    ⟨(@factorThru C _ J _ _ _ f.unop e.unop _).op, Quiver.Hom.unop_inj (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : C
inst✝ : Injective J
E✝ X✝ : Cᵒᵖ
f : op J ⟶ X✝
e : E✝ ⟶ X✝
epi : Epi e
⊢ ((factorThru f.unop e.unop).op ≫ e).unop = f.unop

Next tactic:
simp
instance {P : C} [Projective P] : Injective (op P) where
  factors g f mono :=
    ⟨(@Projective.factorThru C _ P _ _ _ g.unop f.unop _).op, Quiver.Hom.unop_inj (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P : C
inst✝ : Projective P
X✝ Y✝ : Cᵒᵖ
g : X✝ ⟶ op P
f : X✝ ⟶ Y✝
mono : Mono f
⊢ (f ≫ (Projective.factorThru g.unop f.unop).op).unop = g.unop

Next tactic:
simp
theorem injective_iff_preservesEpimorphisms_yoneda_obj (J : C) :
    Injective J ↔ (yoneda.obj J).PreservesEpimorphisms := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
J : C
⊢ Injective J ↔ Functor.PreservesEpimorphisms (yoneda.obj J)

Next tactic:
rw [injective_iff_projective_op, Projective.projective_iff_preservesEpimorphisms_coyoneda_obj]
theorem injective_iff_preservesEpimorphisms_yoneda_obj (J : C) :
    Injective J ↔ (yoneda.obj J).PreservesEpimorphisms := by
  rw [injective_iff_projective_op, Projective.projective_iff_preservesEpimorphisms_coyoneda_obj]
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
J : C
⊢ Functor.PreservesEpimorphisms (coyoneda.obj (op (op J))) ↔ Functor.PreservesEpimorphisms (yoneda.obj J)

Next tactic:
exact Functor.preservesEpimorphisms.iso_iff (Coyoneda.objOpOp _)
theorem injective_of_adjoint (adj : L ⊣ R) (J : D) [Injective J] : Injective <| R.obj J :=
  ⟨fun {A} {_} g f im =>
    ⟨adj.homEquiv _ _ (factorThru ((adj.homEquiv A J).symm g) (L.map f)),
      (adj.homEquiv _ _).symm.injective (by 

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
L : C ⥤ D
R : D ⥤ C
inst✝¹ : PreservesMonomorphisms L
adj : L ⊣ R
J : D
inst✝ : Injective J
A x✝ : C
g : A ⟶ R.obj J
f : A ⟶ x✝
im : Mono f
⊢ (Adjunction.homEquiv adj A J).symm
      (f ≫ (Adjunction.homEquiv adj x✝ J) (factorThru ((Adjunction.homEquiv adj A J).symm g) (L.map f))) =
    (Adjunction.homEquiv adj A J).symm g

Next tactic:
simp
@[simp]
theorem Exact.comp_desc {J Q R S : C} [Injective J] (h : R ⟶ J) (f : Q ⟶ R) (g : R ⟶ S)
    (hgf : Exact g.op f.op) (w : f ≫ h = 0) : g ≫ Exact.desc h f g hgf w = h := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
inst✝² : HasImages Cᵒᵖ
inst✝¹ : HasEqualizers Cᵒᵖ
J Q R S : C
inst✝ : Injective J
h : R ⟶ J
f : Q ⟶ R
g : R ⟶ S
hgf : Exact g.op f.op
w : f ≫ h = 0
⊢ g ≫ desc h f g hgf w = h

Next tactic:
convert congr_arg Quiver.Hom.unop (Exact.lift_comp h.op g.op f.op hgf (congrArg Quiver.Hom.op w))
theorem map_injective (adj : F ⊣ G) [F.PreservesMonomorphisms] (I : D) (hI : Injective I) :
    Injective (G.obj I) :=
  ⟨fun {X} {Y} f g => by
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u_1
inst✝¹ : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesMonomorphisms F
I : D
hI : Injective I
X Y : C
f : X ⟶ G.obj I
g : X ⟶ Y
⊢ ∀ [inst : Mono g], ∃ h, g ≫ h = f

Next tactic:
intro
theorem map_injective (adj : F ⊣ G) [F.PreservesMonomorphisms] (I : D) (hI : Injective I) :
    Injective (G.obj I) :=
  ⟨fun {X} {Y} f g => by
    intro
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u_1
inst✝² : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Functor.PreservesMonomorphisms F
I : D
hI : Injective I
X Y : C
f : X ⟶ G.obj I
g : X ⟶ Y
inst✝ : Mono g
⊢ ∃ h, g ≫ h = f

Next tactic:
rcases hI.factors (F.map f ≫ adj.counit.app _) (F.map g) with ⟨w,h⟩
theorem map_injective (adj : F ⊣ G) [F.PreservesMonomorphisms] (I : D) (hI : Injective I) :
    Injective (G.obj I) :=
  ⟨fun {X} {Y} f g => by
    intro
    rcases hI.factors (F.map f ≫ adj.counit.app _) (F.map g) with ⟨w,h⟩
    

Proof state:
case intro
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u_1
inst✝² : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Functor.PreservesMonomorphisms F
I : D
hI : Injective I
X Y : C
f : X ⟶ G.obj I
g : X ⟶ Y
inst✝ : Mono g
w : F.obj Y ⟶ I
h : F.map g ≫ w = F.map f ≫ adj.counit.app I
⊢ ∃ h, g ≫ h = f

Next tactic:
use adj.unit.app Y ≫ G.map w
theorem map_injective (adj : F ⊣ G) [F.PreservesMonomorphisms] (I : D) (hI : Injective I) :
    Injective (G.obj I) :=
  ⟨fun {X} {Y} f g => by
    intro
    rcases hI.factors (F.map f ≫ adj.counit.app _) (F.map g) with ⟨w,h⟩
    use adj.unit.app Y ≫ G.map w
    

Proof state:
case h
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u_1
inst✝² : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Functor.PreservesMonomorphisms F
I : D
hI : Injective I
X Y : C
f : X ⟶ G.obj I
g : X ⟶ Y
inst✝ : Mono g
w : F.obj Y ⟶ I
h : F.map g ≫ w = F.map f ≫ adj.counit.app I
⊢ g ≫ adj.unit.app Y ≫ G.map w = f

Next tactic:
rw [← unit_naturality_assoc, ← G.map_comp, h]
theorem map_injective (adj : F ⊣ G) [F.PreservesMonomorphisms] (I : D) (hI : Injective I) :
    Injective (G.obj I) :=
  ⟨fun {X} {Y} f g => by
    intro
    rcases hI.factors (F.map f ≫ adj.counit.app _) (F.map g) with ⟨w,h⟩
    use adj.unit.app Y ≫ G.map w
    rw [← unit_naturality_assoc, ← G.map_comp, h]
    

Proof state:
case h
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u_1
inst✝² : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Functor.PreservesMonomorphisms F
I : D
hI : Injective I
X Y : C
f : X ⟶ G.obj I
g : X ⟶ Y
inst✝ : Mono g
w : F.obj Y ⟶ I
h : F.map g ≫ w = F.map f ≫ adj.counit.app I
⊢ adj.unit.app X ≫ G.map (F.map f ≫ adj.counit.app I) = f

Next tactic:
simp
theorem injective_of_map_injective (adj : F ⊣ G) [Full G] [Faithful G] (I : D)
    (hI : Injective (G.obj I)) : Injective I :=
  ⟨fun {X} {Y} f g => by
    

Proof state:
C : Type u₁
inst✝³ : Category.{v₁, u₁} C
D : Type u_1
inst✝² : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝¹ : Full G
inst✝ : Faithful G
I : D
hI : Injective (G.obj I)
X Y : D
f : X ⟶ I
g : X ⟶ Y
⊢ ∀ [inst : Mono g], ∃ h, g ≫ h = f

Next tactic:
intro
theorem injective_of_map_injective (adj : F ⊣ G) [Full G] [Faithful G] (I : D)
    (hI : Injective (G.obj I)) : Injective I :=
  ⟨fun {X} {Y} f g => by
    intro
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u_1
inst✝³ : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝² : Full G
inst✝¹ : Faithful G
I : D
hI : Injective (G.obj I)
X Y : D
f : X ⟶ I
g : X ⟶ Y
inst✝ : Mono g
⊢ ∃ h, g ≫ h = f

Next tactic:
haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits
theorem injective_of_map_injective (adj : F ⊣ G) [Full G] [Faithful G] (I : D)
    (hI : Injective (G.obj I)) : Injective I :=
  ⟨fun {X} {Y} f g => by
    intro
    haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u_1
inst✝³ : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝² : Full G
inst✝¹ : Faithful G
I : D
hI : Injective (G.obj I)
X Y : D
f : X ⟶ I
g : X ⟶ Y
inst✝ : Mono g
this : PreservesLimitsOfSize.{0, 0, u_2, v₁, u_1, u₁} G
⊢ ∃ h, g ≫ h = f

Next tactic:
rcases hI.factors (G.map f) (G.map g) with ⟨w,h⟩
theorem injective_of_map_injective (adj : F ⊣ G) [Full G] [Faithful G] (I : D)
    (hI : Injective (G.obj I)) : Injective I :=
  ⟨fun {X} {Y} f g => by
    intro
    haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits
    rcases hI.factors (G.map f) (G.map g) with ⟨w,h⟩
    

Proof state:
case intro
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u_1
inst✝³ : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝² : Full G
inst✝¹ : Faithful G
I : D
hI : Injective (G.obj I)
X Y : D
f : X ⟶ I
g : X ⟶ Y
inst✝ : Mono g
this : PreservesLimitsOfSize.{0, 0, u_2, v₁, u_1, u₁} G
w : G.obj Y ⟶ G.obj I
h : G.map g ≫ w = G.map f
⊢ ∃ h, g ≫ h = f

Next tactic:
use inv (adj.counit.app _) ≫ F.map w ≫ adj.counit.app _
theorem injective_of_map_injective (adj : F ⊣ G) [Full G] [Faithful G] (I : D)
    (hI : Injective (G.obj I)) : Injective I :=
  ⟨fun {X} {Y} f g => by
    intro
    haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits
    rcases hI.factors (G.map f) (G.map g) with ⟨w,h⟩
    use inv (adj.counit.app _) ≫ F.map w ≫ adj.counit.app _
    

Proof state:
case h
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u_1
inst✝³ : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝² : Full G
inst✝¹ : Faithful G
I : D
hI : Injective (G.obj I)
X Y : D
f : X ⟶ I
g : X ⟶ Y
inst✝ : Mono g
this : PreservesLimitsOfSize.{0, 0, u_2, v₁, u_1, u₁} G
w : G.obj Y ⟶ G.obj I
h : G.map g ≫ w = G.map f
⊢ g ≫ inv (adj.counit.app Y) ≫ F.map w ≫ adj.counit.app I = f

Next tactic:
refine' Faithful.map_injective (F := G) _
theorem injective_of_map_injective (adj : F ⊣ G) [Full G] [Faithful G] (I : D)
    (hI : Injective (G.obj I)) : Injective I :=
  ⟨fun {X} {Y} f g => by
    intro
    haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits
    rcases hI.factors (G.map f) (G.map g) with ⟨w,h⟩
    use inv (adj.counit.app _) ≫ F.map w ≫ adj.counit.app _
    refine' Faithful.map_injective (F := G) _
    

Proof state:
case h
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
D : Type u_1
inst✝³ : Category.{u_2, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝² : Full G
inst✝¹ : Faithful G
I : D
hI : Injective (G.obj I)
X Y : D
f : X ⟶ I
g : X ⟶ Y
inst✝ : Mono g
this : PreservesLimitsOfSize.{0, 0, u_2, v₁, u_1, u₁} G
w : G.obj Y ⟶ G.obj I
h : G.map g ≫ w = G.map f
⊢ G.map (g ≫ inv (adj.counit.app Y) ≫ F.map w ≫ adj.counit.app I) = G.map f

Next tactic:
simpa
/-- Given an adjunction `F ⊣ G` such that `F` preserves monos, `G` maps an injective presentation
of `X` to an injective presentation of `G(X)`. -/
def mapInjectivePresentation (adj : F ⊣ G) [F.PreservesMonomorphisms] (X : D)
    (I : InjectivePresentation X) : InjectivePresentation (G.obj X) where
  J := G.obj I.J
  injective := adj.map_injective _ I.injective
  f := G.map I.f
  mono := by
    

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u_1
inst✝¹ : Category.{?u.56996, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesMonomorphisms F
X : D
I : InjectivePresentation X
⊢ Mono (G.map I.f)

Next tactic:
haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits
/-- Given an adjunction `F ⊣ G` such that `F` preserves monos, `G` maps an injective presentation
of `X` to an injective presentation of `G(X)`. -/
def mapInjectivePresentation (adj : F ⊣ G) [F.PreservesMonomorphisms] (X : D)
    (I : InjectivePresentation X) : InjectivePresentation (G.obj X) where
  J := G.obj I.J
  injective := adj.map_injective _ I.injective
  f := G.map I.f
  mono := by
    haveI : PreservesLimitsOfSize.{0, 0} G := adj.rightAdjointPreservesLimits; 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
D : Type u_1
inst✝¹ : Category.{?u.56996, u_1} D
F : C ⥤ D
G : D ⥤ C
adj : F ⊣ G
inst✝ : Functor.PreservesMonomorphisms F
X : D
I : InjectivePresentation X
this : PreservesLimitsOfSize.{0, 0, ?u.56996, v₁, u_1, u₁} G
⊢ Mono (G.map I.f)

Next tactic:
infer_instance
/-- Let `f : α → α` be a (quasi)ergodic map. Let `g : α → X` is a null-measurable function
from `α` to a nonempty space with a countable family of measurable sets
separating points of a set `s` such that `f x ∈ s` for a.e. `x`.
If `g` that is a.e.-invariant under `f`, then `g` is a.e. constant. -/
theorem QuasiErgodic.ae_eq_const_of_ae_eq_comp_of_ae_range₀ [Nonempty X] [MeasurableSpace X]
    {s : Set X} [HasCountableSeparatingOn X MeasurableSet s] {f : α → α} {g : α → X}
    (h : QuasiErgodic f μ) (hs : ∀ᵐ x ∂μ, g x ∈ s) (hgm : NullMeasurable g μ)
    (hg_eq : g ∘ f =ᵐ[μ] g) :
    ∃ c, g =ᵐ[μ] const α c := by
  

Proof state:
α : Type u_1
X : Type u_2
inst✝³ : MeasurableSpace α
μ : Measure α
inst✝² : Nonempty X
inst✝¹ : MeasurableSpace X
s : Set X
inst✝ : HasCountableSeparatingOn X MeasurableSet s
f : α → α
g : α → X
h : QuasiErgodic f
hs : ∀ᵐ (x : α) ∂μ, g x ∈ s
hgm : NullMeasurable g
hg_eq : g ∘ f =ᵐ[μ] g
⊢ ∃ c, g =ᵐ[μ] const α c

Next tactic:
refine exists_eventuallyEq_const_of_eventually_mem_of_forall_separating MeasurableSet hs ?_
/-- Let `f : α → α` be a (quasi)ergodic map. Let `g : α → X` is a null-measurable function
from `α` to a nonempty space with a countable family of measurable sets
separating points of a set `s` such that `f x ∈ s` for a.e. `x`.
If `g` that is a.e.-invariant under `f`, then `g` is a.e. constant. -/
theorem QuasiErgodic.ae_eq_const_of_ae_eq_comp_of_ae_range₀ [Nonempty X] [MeasurableSpace X]
    {s : Set X} [HasCountableSeparatingOn X MeasurableSet s] {f : α → α} {g : α → X}
    (h : QuasiErgodic f μ) (hs : ∀ᵐ x ∂μ, g x ∈ s) (hgm : NullMeasurable g μ)
    (hg_eq : g ∘ f =ᵐ[μ] g) :
    ∃ c, g =ᵐ[μ] const α c := by
  refine exists_eventuallyEq_const_of_eventually_mem_of_forall_separating MeasurableSet hs ?_
  

Proof state:
α : Type u_1
X : Type u_2
inst✝³ : MeasurableSpace α
μ : Measure α
inst✝² : Nonempty X
inst✝¹ : MeasurableSpace X
s : Set X
inst✝ : HasCountableSeparatingOn X MeasurableSet s
f : α → α
g : α → X
h : QuasiErgodic f
hs : ∀ᵐ (x : α) ∂μ, g x ∈ s
hgm : NullMeasurable g
hg_eq : g ∘ f =ᵐ[μ] g
⊢ ∀ (U : Set X), MeasurableSet U → (∀ᵐ (x : α) ∂μ, g x ∈ U) ∨ ∀ᵐ (x : α) ∂μ, g x ∉ U

Next tactic:
refine fun U hU ↦ h.ae_mem_or_ae_nmem₀ (s := g ⁻¹' U) (hgm hU) ?_b
/-- Let `f : α → α` be a (quasi)ergodic map. Let `g : α → X` is a null-measurable function
from `α` to a nonempty space with a countable family of measurable sets
separating points of a set `s` such that `f x ∈ s` for a.e. `x`.
If `g` that is a.e.-invariant under `f`, then `g` is a.e. constant. -/
theorem QuasiErgodic.ae_eq_const_of_ae_eq_comp_of_ae_range₀ [Nonempty X] [MeasurableSpace X]
    {s : Set X} [HasCountableSeparatingOn X MeasurableSet s] {f : α → α} {g : α → X}
    (h : QuasiErgodic f μ) (hs : ∀ᵐ x ∂μ, g x ∈ s) (hgm : NullMeasurable g μ)
    (hg_eq : g ∘ f =ᵐ[μ] g) :
    ∃ c, g =ᵐ[μ] const α c := by
  refine exists_eventuallyEq_const_of_eventually_mem_of_forall_separating MeasurableSet hs ?_
  refine fun U hU ↦ h.ae_mem_or_ae_nmem₀ (s := g ⁻¹' U) (hgm hU) ?_b
  

Proof state:
case _b
α : Type u_1
X : Type u_2
inst✝³ : MeasurableSpace α
μ : Measure α
inst✝² : Nonempty X
inst✝¹ : MeasurableSpace X
s : Set X
inst✝ : HasCountableSeparatingOn X MeasurableSet s
f : α → α
g : α → X
h : QuasiErgodic f
hs : ∀ᵐ (x : α) ∂μ, g x ∈ s
hgm : NullMeasurable g
hg_eq : g ∘ f =ᵐ[μ] g
U : Set X
hU : MeasurableSet U
⊢ f ⁻¹' (g ⁻¹' U) =ᵐ[μ] g ⁻¹' U

Next tactic:
refine (hg_eq.mono fun x hx ↦ ?_).set_eq
/-- Let `f : α → α` be a (quasi)ergodic map. Let `g : α → X` is a null-measurable function
from `α` to a nonempty space with a countable family of measurable sets
separating points of a set `s` such that `f x ∈ s` for a.e. `x`.
If `g` that is a.e.-invariant under `f`, then `g` is a.e. constant. -/
theorem QuasiErgodic.ae_eq_const_of_ae_eq_comp_of_ae_range₀ [Nonempty X] [MeasurableSpace X]
    {s : Set X} [HasCountableSeparatingOn X MeasurableSet s] {f : α → α} {g : α → X}
    (h : QuasiErgodic f μ) (hs : ∀ᵐ x ∂μ, g x ∈ s) (hgm : NullMeasurable g μ)
    (hg_eq : g ∘ f =ᵐ[μ] g) :
    ∃ c, g =ᵐ[μ] const α c := by
  refine exists_eventuallyEq_const_of_eventually_mem_of_forall_separating MeasurableSet hs ?_
  refine fun U hU ↦ h.ae_mem_or_ae_nmem₀ (s := g ⁻¹' U) (hgm hU) ?_b
  refine (hg_eq.mono fun x hx ↦ ?_).set_eq
  

Proof state:
case _b
α : Type u_1
X : Type u_2
inst✝³ : MeasurableSpace α
μ : Measure α
inst✝² : Nonempty X
inst✝¹ : MeasurableSpace X
s : Set X
inst✝ : HasCountableSeparatingOn X MeasurableSet s
f : α → α
g : α → X
h : QuasiErgodic f
hs : ∀ᵐ (x : α) ∂μ, g x ∈ s
hgm : NullMeasurable g
hg_eq : g ∘ f =ᵐ[μ] g
U : Set X
hU : MeasurableSet U
x : α
hx : (g ∘ f) x = g x
⊢ x ∈ f ⁻¹' (g ⁻¹' U) ↔ x ∈ g ⁻¹' U

Next tactic:
rw [← preimage_comp, mem_preimage, mem_preimage, hx]