l3lab/ntp-mathlib huggingface dataset:
/--
(Implementation). The maps given in `appIso` is inverse to each other and gives a `ℱ(X) ≅ ℱ'(X)`.
-/
@[simps]
noncomputable def appIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val)
    (X : D) : ℱ.val.obj (op X) ≅ ℱ'.val.obj (op X) where
  hom := appHom i.hom X
  inv := appHom i.inv X
  hom_inv_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    

Proof state:
case h.h
C : Type u_1
inst✝⁵ : Category.{?u.66510, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.66517, u_2} D
E : Type u_3
inst✝³ : Category.{?u.66524, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.66576, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
X : D
x : ℱ.val.obj (op X)
⊢ ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X),
    ℱ.val.map f.op ((appHom i.hom X ≫ appHom i.inv X) x) = ℱ.val.map f.op (𝟙 (ℱ.val.obj (op X)) x)

Next tactic:
intro Y f
/--
(Implementation). The maps given in `appIso` is inverse to each other and gives a `ℱ(X) ≅ ℱ'(X)`.
-/
@[simps]
noncomputable def appIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val)
    (X : D) : ℱ.val.obj (op X) ≅ ℱ'.val.obj (op X) where
  hom := appHom i.hom X
  inv := appHom i.inv X
  hom_inv_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y f
    

Proof state:
case h.h
C : Type u_1
inst✝⁵ : Category.{?u.66510, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.66517, u_2} D
E : Type u_3
inst✝³ : Category.{?u.66524, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.66576, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
X : D
x : ℱ.val.obj (op X)
Y : C
f : G.obj Y ⟶ X
⊢ ℱ.val.map f.op ((appHom i.hom X ≫ appHom i.inv X) x) = ℱ.val.map f.op (𝟙 (ℱ.val.obj (op X)) x)

Next tactic:
simp
/--
(Implementation). The maps given in `appIso` is inverse to each other and gives a `ℱ(X) ≅ ℱ'(X)`.
-/
@[simps]
noncomputable def appIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val)
    (X : D) : ℱ.val.obj (op X) ≅ ℱ'.val.obj (op X) where
  hom := appHom i.hom X
  inv := appHom i.inv X
  hom_inv_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y f
    simp
  inv_hom_id := by
    

Proof state:
C : Type u_1
inst✝⁵ : Category.{?u.66510, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.66517, u_2} D
E : Type u_3
inst✝³ : Category.{?u.66524, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.66576, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
X : D
⊢ appHom i.inv X ≫ appHom i.hom X = 𝟙 (ℱ'.val.obj (op X))

Next tactic:
ext x
/--
(Implementation). The maps given in `appIso` is inverse to each other and gives a `ℱ(X) ≅ ℱ'(X)`.
-/
@[simps]
noncomputable def appIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val)
    (X : D) : ℱ.val.obj (op X) ≅ ℱ'.val.obj (op X) where
  hom := appHom i.hom X
  inv := appHom i.inv X
  hom_inv_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y f
    simp
  inv_hom_id := by
    ext x
    

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{?u.66510, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.66517, u_2} D
E : Type u_3
inst✝³ : Category.{?u.66524, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.66576, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
X : D
x : ℱ'.val.obj (op X)
⊢ (appHom i.inv X ≫ appHom i.hom X) x = 𝟙 (ℱ'.val.obj (op X)) x

Next tactic:
apply Functor.IsCoverDense.ext G
/--
(Implementation). The maps given in `appIso` is inverse to each other and gives a `ℱ(X) ≅ ℱ'(X)`.
-/
@[simps]
noncomputable def appIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val)
    (X : D) : ℱ.val.obj (op X) ≅ ℱ'.val.obj (op X) where
  hom := appHom i.hom X
  inv := appHom i.inv X
  hom_inv_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y f
    simp
  inv_hom_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    

Proof state:
case h.h
C : Type u_1
inst✝⁵ : Category.{?u.66510, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.66517, u_2} D
E : Type u_3
inst✝³ : Category.{?u.66524, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.66576, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
X : D
x : ℱ'.val.obj (op X)
⊢ ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X),
    ℱ'.val.map f.op ((appHom i.inv X ≫ appHom i.hom X) x) = ℱ'.val.map f.op (𝟙 (ℱ'.val.obj (op X)) x)

Next tactic:
intro Y f
/--
(Implementation). The maps given in `appIso` is inverse to each other and gives a `ℱ(X) ≅ ℱ'(X)`.
-/
@[simps]
noncomputable def appIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val)
    (X : D) : ℱ.val.obj (op X) ≅ ℱ'.val.obj (op X) where
  hom := appHom i.hom X
  inv := appHom i.inv X
  hom_inv_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y f
    simp
  inv_hom_id := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y f
    

Proof state:
case h.h
C : Type u_1
inst✝⁵ : Category.{?u.66510, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.66517, u_2} D
E : Type u_3
inst✝³ : Category.{?u.66524, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.66576, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val
X : D
x : ℱ'.val.obj (op X)
Y : C
f : G.obj Y ⟶ X
⊢ ℱ'.val.map f.op ((appHom i.inv X ≫ appHom i.hom X) x) = ℱ'.val.map f.op (𝟙 (ℱ'.val.obj (op X)) x)

Next tactic:
simp
/-- Given a natural transformation `G ⋙ ℱ ⟶ G ⋙ ℱ'` between presheaves of types, where `G` is
full and cover-dense, and `ℱ'` is a sheaf, we may obtain a natural transformation between sheaves.
-/
@[simps]
noncomputable def presheafHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) : ℱ ⟶ ℱ'.val where
  app X := appHom α (unop X)
  naturality X Y f := by
    

Proof state:
C : Type u_1
inst✝⁵ : Category.{?u.71415, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.71422, u_2} D
E : Type u_3
inst✝³ : Category.{?u.71429, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.71481, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α✝ α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Dᵒᵖ
f : X ⟶ Y
⊢ ℱ.map f ≫ (fun X => appHom α X.unop) Y = (fun X => appHom α X.unop) X ≫ ℱ'.val.map f

Next tactic:
ext x
/-- Given a natural transformation `G ⋙ ℱ ⟶ G ⋙ ℱ'` between presheaves of types, where `G` is
full and cover-dense, and `ℱ'` is a sheaf, we may obtain a natural transformation between sheaves.
-/
@[simps]
noncomputable def presheafHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) : ℱ ⟶ ℱ'.val where
  app X := appHom α (unop X)
  naturality X Y f := by
    ext x
    

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{?u.71415, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.71422, u_2} D
E : Type u_3
inst✝³ : Category.{?u.71429, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.71481, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α✝ α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Dᵒᵖ
f : X ⟶ Y
x : ℱ.obj X
⊢ (ℱ.map f ≫ (fun X => appHom α X.unop) Y) x = ((fun X => appHom α X.unop) X ≫ ℱ'.val.map f) x

Next tactic:
apply Functor.IsCoverDense.ext G
/-- Given a natural transformation `G ⋙ ℱ ⟶ G ⋙ ℱ'` between presheaves of types, where `G` is
full and cover-dense, and `ℱ'` is a sheaf, we may obtain a natural transformation between sheaves.
-/
@[simps]
noncomputable def presheafHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) : ℱ ⟶ ℱ'.val where
  app X := appHom α (unop X)
  naturality X Y f := by
    ext x
    apply Functor.IsCoverDense.ext G
    

Proof state:
case h.h
C : Type u_1
inst✝⁵ : Category.{?u.71415, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.71422, u_2} D
E : Type u_3
inst✝³ : Category.{?u.71429, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.71481, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α✝ α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Dᵒᵖ
f : X ⟶ Y
x : ℱ.obj X
⊢ ∀ ⦃Y_1 : C⦄ (f_1 : G.obj Y_1 ⟶ Y.unop),
    ℱ'.val.map f_1.op ((ℱ.map f ≫ (fun X => appHom α X.unop) Y) x) =
      ℱ'.val.map f_1.op (((fun X => appHom α X.unop) X ≫ ℱ'.val.map f) x)

Next tactic:
intro Y' f'
/-- Given a natural transformation `G ⋙ ℱ ⟶ G ⋙ ℱ'` between presheaves of types, where `G` is
full and cover-dense, and `ℱ'` is a sheaf, we may obtain a natural transformation between sheaves.
-/
@[simps]
noncomputable def presheafHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) : ℱ ⟶ ℱ'.val where
  app X := appHom α (unop X)
  naturality X Y f := by
    ext x
    apply Functor.IsCoverDense.ext G
    intro Y' f'
    

Proof state:
case h.h
C : Type u_1
inst✝⁵ : Category.{?u.71415, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.71422, u_2} D
E : Type u_3
inst✝³ : Category.{?u.71429, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.71481, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α✝ α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Dᵒᵖ
f : X ⟶ Y
x : ℱ.obj X
Y' : C
f' : G.obj Y' ⟶ Y.unop
⊢ ℱ'.val.map f'.op ((ℱ.map f ≫ (fun X => appHom α X.unop) Y) x) =
    ℱ'.val.map f'.op (((fun X => appHom α X.unop) X ≫ ℱ'.val.map f) x)

Next tactic:
simp only [appHom_restrict, types_comp_apply, ← FunctorToTypes.map_comp_apply]
/-- Given a natural isomorphism `G ⋙ ℱ ≅ G ⋙ ℱ'` between presheaves of types, where `G` is full
and cover-dense, and `ℱ, ℱ'` are sheaves, we may obtain a natural isomorphism between sheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : SheafOfTypes.{v} K} (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.78807, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.78814, u_2} D
E : Type u_3
inst✝³ : Category.{?u.78821, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.78873, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
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 types, where `G` is full
and cover-dense, and `ℱ, ℱ'` are sheaves, we may obtain a natural isomorphism between sheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : SheafOfTypes.{v} K} (i : G.op ⋙ ℱ.val ≅ G.op ⋙ ℱ'.val) :
    ℱ ≅ ℱ' where
  hom := ⟨(presheafIso i).hom⟩
  inv := ⟨(presheafIso i).inv⟩
  hom_inv_id := by
    ext1
    

Proof state:
case w
C : Type u_1
inst✝⁵ : Category.{?u.78807, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.78814, u_2} D
E : Type u_3
inst✝³ : Category.{?u.78821, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.78873, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
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 types, where `G` is full
and cover-dense, and `ℱ, ℱ'` are sheaves, we may obtain a natural isomorphism between sheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : SheafOfTypes.{v} K} (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.78807, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.78814, u_2} D
E : Type u_3
inst✝³ : Category.{?u.78821, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.78873, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
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 types, where `G` is full
and cover-dense, and `ℱ, ℱ'` are sheaves, we may obtain a natural isomorphism between sheaves.
-/
@[simps]
noncomputable def sheafIso {ℱ ℱ' : SheafOfTypes.{v} K} (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 w
C : Type u_1
inst✝⁵ : Category.{?u.78807, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.78814, u_2} D
E : Type u_3
inst✝³ : Category.{?u.78821, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.78873, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ✝ : Dᵒᵖ ⥤ Type v
ℱ'✝ : SheafOfTypes K
α : G.op ⋙ ℱ✝ ⟶ G.op ⋙ ℱ'✝.val
ℱ ℱ' : SheafOfTypes K
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
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    

Proof state:
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
⊢ (coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).map f ≫ (fun X => presheafHom (homOver α X.unop)) Y =
    (fun X => presheafHom (homOver α X.unop)) X ≫ (coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ'.val).map f

Next tactic:
ext U x
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    ext U x
    

Proof state:
case w.h.h
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).map f ≫ (fun X => presheafHom (homOver α X.unop)) Y).app U
      x =
    ((fun X => presheafHom (homOver α X.unop)) X ≫
          (coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ'.val).map f).app
      U x

Next tactic:
change
      appHom (homOver α (unop Y)) (unop U) (f.unop ≫ x) =
        f.unop ≫ appHom (homOver α (unop X)) (unop U) x
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    ext U x
    change
      appHom (homOver α (unop Y)) (unop U) (f.unop ≫ x) =
        f.unop ≫ appHom (homOver α (unop X)) (unop U) x
    

Proof state:
case w.h.h
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ appHom (homOver α Y.unop) U.unop (f.unop ≫ x) = f.unop ≫ appHom (homOver α X.unop) U.unop x

Next tactic:
symm
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    ext U x
    change
      appHom (homOver α (unop Y)) (unop U) (f.unop ≫ x) =
        f.unop ≫ appHom (homOver α (unop X)) (unop U) x
    symm
    

Proof state:
case w.h.h
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ f.unop ≫ appHom (homOver α X.unop) U.unop x = appHom (homOver α Y.unop) U.unop (f.unop ≫ x)

Next tactic:
apply sheaf_eq_amalgamation
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    ext U x
    change
      appHom (homOver α (unop Y)) (unop U) (f.unop ≫ x) =
        f.unop ≫ appHom (homOver α (unop X)) (unop U) x
    symm
    apply sheaf_eq_amalgamation
    

Proof state:
case w.h.h.hT
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ Sieve.coverByImage G U.unop ∈ GrothendieckTopology.sieves K U.unop
case w.h.h.hx
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ FamilyOfElements.Compatible fun Y_1 f_1 h => pushforwardFamily (homOver α Y.unop) (f.unop ≫ x) f_1 h
case w.h.h.h
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ FamilyOfElements.IsAmalgamation (fun Y_1 f_1 h => pushforwardFamily (homOver α Y.unop) (f.unop ≫ x) f_1 h)
    (f.unop ≫ appHom (homOver α X.unop) U.unop x)

Next tactic:
apply G.is_cover_of_isCoverDense
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    ext U x
    change
      appHom (homOver α (unop Y)) (unop U) (f.unop ≫ x) =
        f.unop ≫ appHom (homOver α (unop X)) (unop U) x
    symm
    apply sheaf_eq_amalgamation
    apply G.is_cover_of_isCoverDense
    -- porting note: the following line closes a goal which didn't exist before reenableeta
    · 

Proof state:
case w.h.h.hx
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ FamilyOfElements.Compatible fun Y_1 f_1 h => pushforwardFamily (homOver α Y.unop) (f.unop ≫ x) f_1 h

Next tactic:
exact pushforwardFamily_compatible (homOver α Y.unop) (f.unop ≫ x)
/-- (Implementation). The sheaf map given in `types.sheaf_hom` is natural in terms of `X`. -/
@[simps]
noncomputable def sheafCoyonedaHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) :
    coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ ⟶
      coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type _)).obj ℱ'.val where
  app X := presheafHom (homOver α (unop X))
  naturality X Y f := by
    ext U x
    change
      appHom (homOver α (unop Y)) (unop U) (f.unop ≫ x) =
        f.unop ≫ appHom (homOver α (unop X)) (unop U) x
    symm
    apply sheaf_eq_amalgamation
    apply G.is_cover_of_isCoverDense
    -- porting note: the following line closes a goal which didn't exist before reenableeta
    · exact pushforwardFamily_compatible (homOver α Y.unop) (f.unop ≫ x)
    

Proof state:
case w.h.h.h
C : Type u_1
inst✝⁵ : Category.{?u.83243, u_1} C
D : Type u_2
inst✝⁴ : Category.{?u.83250, u_2} D
E : Type u_3
inst✝³ : Category.{?u.83257, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.86325, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ A
ℱ' : Sheaf K A
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X Y : Aᵒᵖ
f : X ⟶ Y
U : Dᵒᵖ
x : ((coyoneda ⋙ (whiskeringLeft Dᵒᵖ A (Type ?u.86325)).obj ℱ).obj X).obj U
⊢ FamilyOfElements.IsAmalgamation (fun Y_1 f_1 h => pushforwardFamily (homOver α Y.unop) (f.unop ≫ x) f_1 h)
    (f.unop ≫ appHom (homOver α X.unop) U.unop x)

Next tactic:
intro Y' f' hf'