l3lab/ntp-mathlib huggingface dataset:
theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F')
    (l₁ l₂ : (G.sheafify J).toPresheaf ⟶ F')
    (e : Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₁ = Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₂) :
    l₁ = l₂ := by
  ext U ⟨s, hs⟩
  

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : toPresheaf (sheafify J G) ⟶ F'
e : homOfLe (_ : G ≤ sheafify J G) ≫ l₁ = homOfLe (_ : G ≤ sheafify J G) ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
⊢ l₁.app U { val := s, property := hs } = l₂.app U { val := s, property := hs }

Next tactic:
apply (h _ hs).isSeparatedFor.ext
theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F')
    (l₁ l₂ : (G.sheafify J).toPresheaf ⟶ F')
    (e : Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₁ = Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₂) :
    l₁ = l₂ := by
  ext U ⟨s, hs⟩
  apply (h _ hs).isSeparatedFor.ext
  

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : toPresheaf (sheafify J G) ⟶ F'
e : homOfLe (_ : G ≤ sheafify J G) ≫ l₁ = homOfLe (_ : G ≤ sheafify J G) ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
⊢ ∀ ⦃Y : C⦄ ⦃f : Y ⟶ U.unop⦄,
    (sieveOfSection G s).arrows f →
      F'.map f.op (l₁.app U { val := s, property := hs }) = F'.map f.op (l₂.app U { val := s, property := hs })

Next tactic:
rintro V i hi
theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F')
    (l₁ l₂ : (G.sheafify J).toPresheaf ⟶ F')
    (e : Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₁ = Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₂) :
    l₁ = l₂ := by
  ext U ⟨s, hs⟩
  apply (h _ hs).isSeparatedFor.ext
  rintro V i hi
  

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : toPresheaf (sheafify J G) ⟶ F'
e : homOfLe (_ : G ≤ sheafify J G) ≫ l₁ = homOfLe (_ : G ≤ sheafify J G) ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : (sieveOfSection G s).arrows i
⊢ F'.map i.op (l₁.app U { val := s, property := hs }) = F'.map i.op (l₂.app U { val := s, property := hs })

Next tactic:
dsimp at hi
theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F')
    (l₁ l₂ : (G.sheafify J).toPresheaf ⟶ F')
    (e : Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₁ = Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₂) :
    l₁ = l₂ := by
  ext U ⟨s, hs⟩
  apply (h _ hs).isSeparatedFor.ext
  rintro V i hi
  dsimp at hi
  

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : toPresheaf (sheafify J G) ⟶ F'
e : homOfLe (_ : G ≤ sheafify J G) ≫ l₁ = homOfLe (_ : G ≤ sheafify J G) ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : F.map i.op s ∈ obj G (op V)
⊢ F'.map i.op (l₁.app U { val := s, property := hs }) = F'.map i.op (l₂.app U { val := s, property := hs })

Next tactic:
erw [← FunctorToTypes.naturality, ← FunctorToTypes.naturality]
theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F')
    (l₁ l₂ : (G.sheafify J).toPresheaf ⟶ F')
    (e : Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₁ = Subpresheaf.homOfLe (G.le_sheafify J) ≫ l₂) :
    l₁ = l₂ := by
  ext U ⟨s, hs⟩
  apply (h _ hs).isSeparatedFor.ext
  rintro V i hi
  dsimp at hi
  erw [← FunctorToTypes.naturality, ← FunctorToTypes.naturality]
  

Proof state:
case w.h.h.mk
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : Presieve.IsSheaf J F'
l₁ l₂ : toPresheaf (sheafify J G) ⟶ F'
e : homOfLe (_ : G ≤ sheafify J G) ≫ l₁ = homOfLe (_ : G ≤ sheafify J G) ≫ l₂
U : Cᵒᵖ
s : F.obj U
hs : s ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : F.map i.op s ∈ obj G (op V)
⊢ l₁.app (op V) ((toPresheaf (sheafify J G)).map i.op { val := s, property := hs }) =
    l₂.app (op V) ((toPresheaf (sheafify J G)).map i.op { val := s, property := hs })

Next tactic:
exact (congr_fun (congr_app e <| op V) ⟨_, hi⟩ : _)
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
⊢ sheafify J G ≤ G'

Next tactic:
intro U x hx
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
⊢ x ∈ obj G' U

Next tactic:
convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
⊢ x = ↑((sheafifyLift G (homOfLe h) hG').app U { val := x, property := hx })

Next tactic:
apply (hF _ hx).isSeparatedFor.ext
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
  apply (hF _ hx).isSeparatedFor.ext
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
⊢ ∀ ⦃Y : C⦄ ⦃f : Y ⟶ U.unop⦄,
    (sieveOfSection G x).arrows f →
      F.map f.op x = F.map f.op ↑((sheafifyLift G (homOfLe h) hG').app U { val := x, property := hx })

Next tactic:
intro V i hi
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
  apply (hF _ hx).isSeparatedFor.ext
  intro V i hi
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : (sieveOfSection G x).arrows i
⊢ F.map i.op x = F.map i.op ↑((sheafifyLift G (homOfLe h) hG').app U { val := x, property := hx })

Next tactic:
have :=
    congr_arg (fun f : G.toPresheaf ⟶ G'.toPresheaf => (NatTrans.app f (op V) ⟨_, hi⟩).1)
      (G.to_sheafifyLift (Subpresheaf.homOfLe h) hG')
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
  apply (hF _ hx).isSeparatedFor.ext
  intro V i hi
  have :=
    congr_arg (fun f : G.toPresheaf ⟶ G'.toPresheaf => (NatTrans.app f (op V) ⟨_, hi⟩).1)
      (G.to_sheafifyLift (Subpresheaf.homOfLe h) hG')
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : (sieveOfSection G x).arrows i
this :
  (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi }))
      (homOfLe (_ : G ≤ sheafify J G) ≫ sheafifyLift G (homOfLe h) hG') =
    (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi })) (homOfLe h)
⊢ F.map i.op x = F.map i.op ↑((sheafifyLift G (homOfLe h) hG').app U { val := x, property := hx })

Next tactic:
convert this.symm
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
  apply (hF _ hx).isSeparatedFor.ext
  intro V i hi
  have :=
    congr_arg (fun f : G.toPresheaf ⟶ G'.toPresheaf => (NatTrans.app f (op V) ⟨_, hi⟩).1)
      (G.to_sheafifyLift (Subpresheaf.homOfLe h) hG')
  convert this.symm
  

Proof state:
case h.e'_3
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : (sieveOfSection G x).arrows i
this :
  (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi }))
      (homOfLe (_ : G ≤ sheafify J G) ≫ sheafifyLift G (homOfLe h) hG') =
    (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi })) (homOfLe h)
⊢ F.map i.op ↑((sheafifyLift G (homOfLe h) hG').app U { val := x, property := hx }) =
    (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi }))
      (homOfLe (_ : G ≤ sheafify J G) ≫ sheafifyLift G (homOfLe h) hG')

Next tactic:
erw [← Subpresheaf.nat_trans_naturality]
theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F)
    (hG' : Presieve.IsSheaf J G'.toPresheaf) : G.sheafify J ≤ G' := by
  intro U x hx
  convert ((G.sheafifyLift (Subpresheaf.homOfLe h) hG').app U ⟨x, hx⟩).2
  apply (hF _ hx).isSeparatedFor.ext
  intro V i hi
  have :=
    congr_arg (fun f : G.toPresheaf ⟶ G'.toPresheaf => (NatTrans.app f (op V) ⟨_, hi⟩).1)
      (G.to_sheafifyLift (Subpresheaf.homOfLe h) hG')
  convert this.symm
  erw [← Subpresheaf.nat_trans_naturality]
  

Proof state:
case h.e'_3
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
h : G ≤ G'
hF : Presieve.IsSheaf J F
hG' : Presieve.IsSheaf J (toPresheaf G')
U : Cᵒᵖ
x : F.obj U
hx : x ∈ obj (sheafify J G) U
V : C
i : V ⟶ U.unop
hi : (sieveOfSection G x).arrows i
this :
  (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi }))
      (homOfLe (_ : G ≤ sheafify J G) ≫ sheafifyLift G (homOfLe h) hG') =
    (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi })) (homOfLe h)
⊢ ↑((sheafifyLift G (homOfLe h) hG').app (op V) ((toPresheaf (sheafify J G)).map i.op { val := x, property := hx })) =
    (fun f => ↑(f.app (op V) { val := F.map i.op x, property := hi }))
      (homOfLe (_ : G ≤ sheafify J G) ≫ sheafifyLift G (homOfLe h) hG')

Next tactic:
rfl
/-- The image presheaf of a morphism, whose components are the set-theoretic images. -/
@[simps]
def imagePresheaf (f : F' ⟶ F) : Subpresheaf F where
  obj U := Set.range (f.app U)
  map := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
⊢ ∀ {U V : Cᵒᵖ} (i : U ⟶ V), (fun U => Set.range (f.app U)) U ⊆ F.map i ⁻¹' (fun U => Set.range (f.app U)) V

Next tactic:
rintro U V i _ ⟨x, rfl⟩
/-- The image presheaf of a morphism, whose components are the set-theoretic images. -/
@[simps]
def imagePresheaf (f : F' ⟶ F) : Subpresheaf F where
  obj U := Set.range (f.app U)
  map := by
    rintro U V i _ ⟨x, rfl⟩
    

Proof state:
case intro
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
U V : Cᵒᵖ
i : U ⟶ V
x : F'.obj U
⊢ f.app U x ∈ F.map i ⁻¹' (fun U => Set.range (f.app U)) V

Next tactic:
have := elementwise_of% f.naturality
/-- The image presheaf of a morphism, whose components are the set-theoretic images. -/
@[simps]
def imagePresheaf (f : F' ⟶ F) : Subpresheaf F where
  obj U := Set.range (f.app U)
  map := by
    rintro U V i _ ⟨x, rfl⟩
    have := elementwise_of% f.naturality
    

Proof state:
case intro
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
f : F' ⟶ F
U V : Cᵒᵖ
i : U ⟶ V
x : F'.obj U
this : ∀ ⦃X Y : Cᵒᵖ⦄ (f_1 : X ⟶ Y) (x : F'.obj X), f.app Y (F'.map f_1 x) = F.map f_1 (f.app X x)
⊢ f.app U x ∈ F.map i ⁻¹' (fun U => Set.range (f.app U)) V

Next tactic:
exact ⟨_, this i x⟩
@[simp]
theorem imagePresheaf_id : imagePresheaf (𝟙 F) = ⊤ := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
⊢ imagePresheaf (𝟙 F) = ⊤

Next tactic:
ext
@[simp]
theorem imagePresheaf_id : imagePresheaf (𝟙 F) = ⊤ := by
  ext
  

Proof state:
case obj.h.h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F F' F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F
x✝¹ : Cᵒᵖ
x✝ : F.obj x✝¹
⊢ x✝ ∈ Subpresheaf.obj (imagePresheaf (𝟙 F)) x✝¹ ↔ x✝ ∈ Subpresheaf.obj ⊤ x✝¹

Next tactic:
simp
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
⊢ IsIso (toImagePresheaf f)

Next tactic:
have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      have := (NatTrans.mono_iff_mono_app _ _).mp hf X
      rw [mono_iff_injective] at this
      exact this (congr_arg Subtype.val e : _)
    · rintro ⟨_, ⟨x, rfl⟩⟩
      exact ⟨x, rfl⟩
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
⊢ ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X)

Next tactic:
intro X
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
⊢ IsIso ((toImagePresheaf f).app X)

Next tactic:
rw [isIso_iff_bijective]
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
⊢ Function.Bijective ((toImagePresheaf f).app X)

Next tactic:
constructor
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · 

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
⊢ Function.Injective ((toImagePresheaf f).app X)

Next tactic:
intro x y e
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
x y : F.obj X
e : (toImagePresheaf f).app X x = (toImagePresheaf f).app X y
⊢ x = y

Next tactic:
have := (NatTrans.mono_iff_mono_app _ _).mp hf X
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      have := (NatTrans.mono_iff_mono_app _ _).mp hf X
      

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
x y : F.obj X
e : (toImagePresheaf f).app X x = (toImagePresheaf f).app X y
this : Mono (f.app X)
⊢ x = y

Next tactic:
rw [mono_iff_injective] at this
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      have := (NatTrans.mono_iff_mono_app _ _).mp hf X
      rw [mono_iff_injective] at this
      

Proof state:
case left
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
x y : F.obj X
e : (toImagePresheaf f).app X x = (toImagePresheaf f).app X y
this : Function.Injective (f.app X)
⊢ x = y

Next tactic:
exact this (congr_arg Subtype.val e : _)
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      have := (NatTrans.mono_iff_mono_app _ _).mp hf X
      rw [mono_iff_injective] at this
      exact this (congr_arg Subtype.val e : _)
    · 

Proof state:
case right
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
⊢ Function.Surjective ((toImagePresheaf f).app X)

Next tactic:
rintro ⟨_, ⟨x, rfl⟩⟩
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      have := (NatTrans.mono_iff_mono_app _ _).mp hf X
      rw [mono_iff_injective] at this
      exact this (congr_arg Subtype.val e : _)
    · rintro ⟨_, ⟨x, rfl⟩⟩
      

Proof state:
case right.mk.intro
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
X : Cᵒᵖ
x : F.obj X
⊢ ∃ a, (toImagePresheaf f).app X a = { val := f.app X x, property := (_ : ∃ y, f.app X y = f.app X x) }

Next tactic:
exact ⟨x, rfl⟩
instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] :
  IsIso (toImagePresheaf f) := by
  have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by
    intro X
    rw [isIso_iff_bijective]
    constructor
    · intro x y e
      have := (NatTrans.mono_iff_mono_app _ _).mp hf X
      rw [mono_iff_injective] at this
      exact this (congr_arg Subtype.val e : _)
    · rintro ⟨_, ⟨x, rfl⟩⟩
      exact ⟨x, rfl⟩
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Cᵒᵖ ⥤ TypeMax
f : F ⟶ F'
hf : Mono f
this : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X)
⊢ IsIso (toImagePresheaf f)

Next tactic:
apply NatIso.isIso_of_isIso_app
/-- The image sheaf of a morphism between sheaves, defined to be the sheafification of
`image_presheaf`. -/
@[simps]
def imageSheaf {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Sheaf J (Type w) :=
  ⟨((imagePresheaf f.1).sheafify J).toPresheaf, by
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Presheaf.IsSheaf J (Subpresheaf.toPresheaf (Subpresheaf.sheafify J (imagePresheaf f.val)))

Next tactic:
rw [isSheaf_iff_isSheaf_of_type]
/-- The image sheaf of a morphism between sheaves, defined to be the sheafification of
`image_presheaf`. -/
@[simps]
def imageSheaf {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Sheaf J (Type w) :=
  ⟨((imagePresheaf f.1).sheafify J).toPresheaf, by
    rw [isSheaf_iff_isSheaf_of_type]
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Presieve.IsSheaf J (Subpresheaf.toPresheaf (Subpresheaf.sheafify J (imagePresheaf f.val)))

Next tactic:
apply Subpresheaf.sheafify_isSheaf
/-- The image sheaf of a morphism between sheaves, defined to be the sheafification of
`image_presheaf`. -/
@[simps]
def imageSheaf {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Sheaf J (Type w) :=
  ⟨((imagePresheaf f.1).sheafify J).toPresheaf, by
    rw [isSheaf_iff_isSheaf_of_type]
    apply Subpresheaf.sheafify_isSheaf
    

Proof state:
case hF
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Presieve.IsSheaf J F'.val

Next tactic:
rw [← isSheaf_iff_isSheaf_of_type]
/-- The image sheaf of a morphism between sheaves, defined to be the sheafification of
`image_presheaf`. -/
@[simps]
def imageSheaf {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Sheaf J (Type w) :=
  ⟨((imagePresheaf f.1).sheafify J).toPresheaf, by
    rw [isSheaf_iff_isSheaf_of_type]
    apply Subpresheaf.sheafify_isSheaf
    rw [← isSheaf_iff_isSheaf_of_type]
    

Proof state:
case hF
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Presheaf.IsSheaf J F'.val

Next tactic:
exact F'.2
@[reassoc (attr := simp)]
theorem toImageSheaf_ι {F F' : Sheaf J (Type w)} (f : F ⟶ F') :
    toImageSheaf f ≫ imageSheafι f = f := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ toImageSheaf f ≫ imageSheafι f = f

Next tactic:
ext1
@[reassoc (attr := simp)]
theorem toImageSheaf_ι {F F' : Sheaf J (Type w)} (f : F ⟶ F') :
    toImageSheaf f ≫ imageSheafι f = f := by
  ext1
  

Proof state:
case h
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ (toImageSheaf f ≫ imageSheafι f).val = f.val

Next tactic:
simp [toImagePresheafSheafify]
instance {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Mono (imageSheafι f) :=
  (sheafToPresheaf J _).mono_of_mono_map
    (by
      

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Mono ((sheafToPresheaf J (Type w)).map (imageSheafι f))

Next tactic:
dsimp
instance {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Mono (imageSheafι f) :=
  (sheafToPresheaf J _).mono_of_mono_map
    (by
      dsimp
      

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Mono (Subpresheaf.ι (Subpresheaf.sheafify J (imagePresheaf f.val)))

Next tactic:
infer_instance
instance {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Epi (toImageSheaf f) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
J : GrothendieckTopology C
F✝ F'✝ F'' : Cᵒᵖ ⥤ Type w
G G' : Subpresheaf F✝
F F' : Sheaf J (Type w)
f : F ⟶ F'
⊢ Epi (toImageSheaf f)

Next tactic:
refine' ⟨@fun G' g₁ g₂ e => _⟩