l3lab/ntp-mathlib huggingface dataset:
/-- Given a natural isomorphism `G ⋙ ℱ ≅ G ⋙ ℱ'` between presheaves of arbitrary category,
where `G` is full and cover-dense, and `ℱ', ℱ` are sheaves,
we may obtain a natural isomorphism between presheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : Sheaf K A} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val) : ℱ ≅ ℱ' where
  hom := ⟨(presheafIso i).hom⟩
  inv := ⟨(presheafIso i).inv⟩
  hom_inv_id := by
    

Proof state:
C : Type u_1
inst✝⁵ : Category.{?u.118795, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.118802, u_2} D
E : Type u_3
inst✝³ : Category.{?u.118809, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.118861, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ A
ℱ'✝ ℱ ℱ' : Sheaf K A
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
⊢ { val := (presheafIso i).hom } ≫ { val := (presheafIso i).inv } = 𝟙 ℱ

Next tactic:
ext1
/-- Given a natural isomorphism `G ⋙ ℱ ≅ G ⋙ ℱ'` between presheaves of arbitrary category,
where `G` is full and cover-dense, and `ℱ', ℱ` are sheaves,
we may obtain a natural isomorphism between presheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : Sheaf K A} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val) : ℱ ≅ ℱ' where
  hom := ⟨(presheafIso i).hom⟩
  inv := ⟨(presheafIso i).inv⟩
  hom_inv_id := by
    ext1
    

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{?u.118795, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.118802, u_2} D
E : Type u_3
inst✝³ : Category.{?u.118809, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.118861, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ A
ℱ'✝ ℱ ℱ' : Sheaf K A
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
⊢ ({ val := (presheafIso i).hom } ≫ { val := (presheafIso i).inv }).val = (𝟙 ℱ).val

Next tactic:
apply (presheafIso i).hom_inv_id
/-- Given a natural isomorphism `G ⋙ ℱ ≅ G ⋙ ℱ'` between presheaves of arbitrary category,
where `G` is full and cover-dense, and `ℱ', ℱ` are sheaves,
we may obtain a natural isomorphism between presheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : Sheaf K A} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val) : ℱ ≅ ℱ' where
  hom := ⟨(presheafIso i).hom⟩
  inv := ⟨(presheafIso i).inv⟩
  hom_inv_id := by
    ext1
    apply (presheafIso i).hom_inv_id
  inv_hom_id := by
    

Proof state:
C : Type u_1
inst✝⁵ : Category.{?u.118795, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.118802, u_2} D
E : Type u_3
inst✝³ : Category.{?u.118809, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.118861, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ A
ℱ'✝ ℱ ℱ' : Sheaf K A
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
⊢ { val := (presheafIso i).inv } ≫ { val := (presheafIso i).hom } = 𝟙 ℱ'

Next tactic:
ext1
/-- Given a natural isomorphism `G ⋙ ℱ ≅ G ⋙ ℱ'` between presheaves of arbitrary category,
where `G` is full and cover-dense, and `ℱ', ℱ` are sheaves,
we may obtain a natural isomorphism between presheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : Sheaf K A} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val) : ℱ ≅ ℱ' where
  hom := ⟨(presheafIso i).hom⟩
  inv := ⟨(presheafIso i).inv⟩
  hom_inv_id := by
    ext1
    apply (presheafIso i).hom_inv_id
  inv_hom_id := by
    ext1
    

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{?u.118795, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.118802, u_2} D
E : Type u_3
inst✝³ : Category.{?u.118809, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.118861, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ A
ℱ'✝ ℱ ℱ' : Sheaf K A
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
⊢ ({ val := (presheafIso i).inv } ≫ { val := (presheafIso i).hom }).val = (𝟙 ℱ').val

Next tactic:
apply (presheafIso i).inv_hom_id
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  

Proof state:
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
⊢ whiskerLeft G.op (sheafHom α) = α

Next tactic:
ext X
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  

Proof state:
case w.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
⊢ (whiskerLeft G.op (sheafHom α)).app X = α.app X

Next tactic:
apply yoneda.map_injective
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  

Proof state:
case w.h.a
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
⊢ yoneda.map ((whiskerLeft G.op (sheafHom α)).app X) = yoneda.map (α.app X)

Next tactic:
ext U
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  

Proof state:
case w.h.a.w.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
⊢ (yoneda.map ((whiskerLeft G.op (sheafHom α)).app X)).app U a✝ = (yoneda.map (α.app X)).app U a✝

Next tactic:
erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  

Proof state:
case w.h.a.w.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
⊢ ((sheafYonedaHom α).app (G.op.obj X)).app U a✝ = (yoneda.map (α.app X)).app U a✝

Next tactic:
symm
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  

Proof state:
case w.h.a.w.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
⊢ (yoneda.map (α.app X)).app U a✝ = ((sheafYonedaHom α).app (G.op.obj X)).app U a✝

Next tactic:
change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  

Proof state:
case w.h.a.w.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
⊢ (let_fun this := (yoneda.map (α.app X)).app U a✝;
    this) =
    ((sheafYonedaHom α).app (G.op.obj X)).app U a✝

Next tactic:
apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · 

Proof state:
case w.h.a.w.h.h.hx
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
⊢ FamilyOfElements.Compatible (pushforwardFamily (homOver α U.unop) a✝)

Next tactic:
exact (pushforwardFamily_compatible _ _)
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  

Proof state:
case w.h.a.w.h.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
⊢ FamilyOfElements.IsAmalgamation (pushforwardFamily (homOver α U.unop) a✝)
    (let_fun this := (yoneda.map (α.app X)).app U a✝;
    this)

Next tactic:
intro Y f hf
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  

Proof state:
case w.h.a.w.h.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
⊢ (ℱ'.val ⋙ coyoneda.obj (op U.unop)).map f.op
      (let_fun this := (yoneda.map (α.app X)).app U a✝;
      this) =
    pushforwardFamily (homOver α U.unop) a✝ f hf

Next tactic:
conv_lhs => rw [← hf.some.fac]
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  conv_lhs => 

Proof state:
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
| (ℱ'.val ⋙ coyoneda.obj (op U.unop)).map f.op
    (let_fun this := (yoneda.map (α.app X)).app U a✝;
    this)

Next tactic:
rw [← hf.some.fac]
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  conv_lhs => rw [← hf.some.fac]
  

Proof state:
case w.h.a.w.h.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
⊢ (ℱ'.val ⋙ coyoneda.obj (op U.unop)).map ((Nonempty.some hf).lift ≫ (Nonempty.some hf).map).op
      (let_fun this := (yoneda.map (α.app X)).app U a✝;
      this) =
    pushforwardFamily (homOver α U.unop) a✝ f hf

Next tactic:
simp only [pushforwardFamily, Functor.comp_map, yoneda_map_app, coyoneda_obj_map, op_comp,
    FunctorToTypes.map_comp_apply, homOver_app, ← Category.assoc]
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  conv_lhs => rw [← hf.some.fac]
  simp only [pushforwardFamily, Functor.comp_map, yoneda_map_app, coyoneda_obj_map, op_comp,
    FunctorToTypes.map_comp_apply, homOver_app, ← Category.assoc]
  

Proof state:
case w.h.a.w.h.h.h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
⊢ ((a✝ ≫ α.app X) ≫ ℱ'.val.map (Nonempty.some hf).map.op) ≫ ℱ'.val.map (Nonempty.some hf).lift.op =
    (sheafOver ℱ' U.unop).val.map (Nonempty.some hf).lift.op
      ((a✝ ≫ ℱ.map (Nonempty.some hf).map.op) ≫ α.app (op (Nonempty.some hf).1))

Next tactic:
congr 1
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  conv_lhs => rw [← hf.some.fac]
  simp only [pushforwardFamily, Functor.comp_map, yoneda_map_app, coyoneda_obj_map, op_comp,
    FunctorToTypes.map_comp_apply, homOver_app, ← Category.assoc]
  congr 1
  

Proof state:
case w.h.a.w.h.h.h.e_a
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
⊢ (a✝ ≫ α.app X) ≫ ℱ'.val.map (Nonempty.some hf).map.op =
    (a✝ ≫ ℱ.map (Nonempty.some hf).map.op) ≫ α.app (op (Nonempty.some hf).1)

Next tactic:
simp only [Category.assoc]
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  conv_lhs => rw [← hf.some.fac]
  simp only [pushforwardFamily, Functor.comp_map, yoneda_map_app, coyoneda_obj_map, op_comp,
    FunctorToTypes.map_comp_apply, homOver_app, ← Category.assoc]
  congr 1
  simp only [Category.assoc]
  

Proof state:
case w.h.a.w.h.h.h.e_a
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
⊢ a✝ ≫ α.app X ≫ ℱ'.val.map (Nonempty.some hf).map.op =
    a✝ ≫ ℱ.map (Nonempty.some hf).map.op ≫ α.app (op (Nonempty.some hf).1)

Next tactic:
congr 1
/-- The constructed `sheafHom α` is equal to `α` when restricted onto `C`.
-/
theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    whiskerLeft G.op (sheafHom α) = α := by
  ext X
  apply yoneda.map_injective
  ext U
  -- porting note: didn't need to provide the input to `image_preimage` in Lean 3
  erw [yoneda.image_preimage ((sheafYonedaHom α).app (G.op.obj X))]
  symm
  change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _
  apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _)
  -- porting note: next line was not needed in mathlib3
  · exact (pushforwardFamily_compatible _ _)
  intro Y f hf
  conv_lhs => rw [← hf.some.fac]
  simp only [pushforwardFamily, Functor.comp_map, yoneda_map_app, coyoneda_obj_map, op_comp,
    FunctorToTypes.map_comp_apply, homOver_app, ← Category.assoc]
  congr 1
  simp only [Category.assoc]
  congr 1
  

Proof state:
case w.h.a.w.h.h.h.e_a.e_a
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_7, u_2} D
E : Type u_3
inst✝³ : Category.{?u.122032, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{u_5, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : Cᵒᵖ
U : Aᵒᵖ
a✝ : (yoneda.obj ((G.op ⋙ ℱ).obj X)).obj U
Y : D
f : Y ⟶ G.obj X.unop
hf : (Sieve.coverByImage G (G.obj X.unop)).arrows f
⊢ α.app X ≫ ℱ'.val.map (Nonempty.some hf).map.op = ℱ.map (Nonempty.some hf).map.op ≫ α.app (op (Nonempty.some hf).1)

Next tactic:
rw [← G.image_preimage hf.some.map]