-- Mathlib/CategoryTheory/Sites/DenseSubsite/SheafEquiv.lean
lemma isIso_ranCounit_app_of_isDenseSubsite (Y : Sheaf J A) (U X) :
    IsIso ((yoneda.map ((G.op.ranCounit.app Y.val).app (op U))).app (op X))

Proof state:
case refine_2.mk.mk.unit.op.mk.mk.unit.op.mk.up.up.refl
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
l : (X Y Z : C) → (f : X ⟶ Y) → (g : G.obj Y ⟶ G.obj Z) → (G.imageSieve g).arrows f → (X ⟶ Z)
hl :
  ∀ (X Y Z : C) (f : X ⟶ Y) (g : G.obj Y ⟶ G.obj Z) (hf : (G.imageSieve g).arrows f),
    G.map (l X Y Z f g hf) = G.map f ≫ g
W₁ : C
g₁ : op (G.obj U) ⟶ op (G.obj W₁)
W₂ : C
g₂ : op (G.obj U) ⟶ op (G.obj W₂)
i : op W₁ ⟶ op W₂
hi : 𝟙 (op (G.obj U)) ≫ g₂ = g₁ ≫ (G.map i.unop).op
⊢ 𝟙 X ≫
      ⋯.amalgamate ⟨G.imageSieve { left := { as := PUnit.unit }, right := op W₂, hom := g₂ }.hom.unop, ⋯⟩
        (fun I =>
          f ≫
            Y.val.map
              (l I.Y (unop { left := { as := PUnit.unit }, right := op W₂, hom := g₂ }.2) U I.f
                  { left := { as := PUnit.unit }, right := op W₂, hom := g₂ }.hom.unop ⋯).op)
        ⋯ =
    ⋯.amalgamate ⟨G.imageSieve { left := { as := PUnit.unit }, right := op W₁, hom := g₁ }.hom.unop, ⋯⟩
        (fun I =>
          f ≫
            Y.val.map
              (l I.Y (unop { left := { as := PUnit.unit }, right := op W₁, hom := g₁ }.2) U I.f
                  { left := { as := PUnit.unit }, right := op W₁, hom := g₁ }.hom.unop ⋯).op)
        ⋯ ≫
      Y.val.map { left := { down := { down := ⋯ } }, right := i, w := hi }.right

Tactic:
have h : g₂ = g₁ ≫ (G.map i.unop).op := by simpa only [Category.id_comp] using hi

Result:
case refine_2.mk.mk.unit.op.mk.mk.unit.op.mk.up.up.refl
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
l : (X Y Z : C) → (f : X ⟶ Y) → (g : G.obj Y ⟶ G.obj Z) → (G.imageSieve g).arrows f → (X ⟶ Z)
hl :
  ∀ (X Y Z : C) (f : X ⟶ Y) (g : G.obj Y ⟶ G.obj Z) (hf : (G.imageSieve g).arrows f),
    G.map (l X Y Z f g hf) = G.map f ≫ g
W₁ : C
g₁ : op (G.obj U) ⟶ op (G.obj W₁)
W₂ : C
g₂ : op (G.obj U) ⟶ op (G.obj W₂)
i : op W₁ ⟶ op W₂
hi : 𝟙 (op (G.obj U)) ≫ g₂ = g₁ ≫ (G.map i.unop).op
h : g₂ = g₁ ≫ (G.map i.unop).op
⊢ 𝟙 X ≫
      ⋯.amalgamate ⟨G.imageSieve { left := { as := PUnit.unit }, right := op W₂, hom := g₂ }.hom.unop, ⋯⟩
        (fun I =>
          f ≫
            Y.val.map
              (l I.Y (unop { left := { as := PUnit.unit }, right := op W₂, hom := g₂ }.2) U I.f
                  { left := { as := PUnit.unit }, right := op W₂, hom := g₂ }.hom.unop ⋯).op)
        ⋯ =
    ⋯.amalgamate ⟨G.imageSieve { left := { as := PUnit.unit }, right := op W₁, hom := g₁ }.hom.unop, ⋯⟩
        (fun I =>
          f ≫
            Y.val.map
              (l I.Y (unop { left := { as := PUnit.unit }, right := op W₁, hom := g₁ }.2) U I.f
                  { left := { as := PUnit.unit }, right := op W₁, hom := g₁ }.hom.unop ⋯).op)
        ⋯ ≫
      Y.val.map { left := { down := { down := ⋯ } }, right := i, w := hi }.right

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
l : (X Y Z : C) → (f : X ⟶ Y) → (g : G.obj Y ⟶ G.obj Z) → (G.imageSieve g).arrows f → (X ⟶ Z)
hl :
  ∀ (X Y Z : C) (f : X ⟶ Y) (g : G.obj Y ⟶ G.obj Z) (hf : (G.imageSieve g).arrows f),
    G.map (l X Y Z f g hf) = G.map f ≫ g
W₁ W₂ : C
g : G.obj W₁ ⟶ G.obj U
i : W₂ ⟶ W₁
hi : 𝟙 (op (G.obj U)) ≫ g.op ≫ (G.map i.op.unop).op = g.op ≫ (G.map i.op.unop).op
I : GrothendieckTopology.Cover.Arrow ⟨G.imageSieve (G.map i ≫ g), ⋯⟩
I' : GrothendieckTopology.Cover.Arrow ⟨G.imageSieve g, ⋯⟩ := { Y := I.Y, f := I.f ≫ i, hf := ⋯ }
V : C
iUV : V ⟶ I.Y
hiUV : iUV ≫ l I.Y W₂ U I.f (G.map i ≫ g) ⋯ = iUV ≫ l I.Y W₁ U I'.f g ⋯
⊢ (Y.val ⋙ coyoneda.obj (op X)).map iUV.op (f ≫ Y.val.map (l I.Y W₂ U I.f (G.map i ≫ g) ⋯).op) =
    (Y.val ⋙ coyoneda.obj (op X)).map iUV.op (f ≫ Y.val.map (l I'.Y W₁ U I'.f g ⋯).op)

Tactic:
simp [I', ← Functor.map_comp, ← op_comp, hiUV]

Result:
no goals

Proof state:
C : Type u_1
D : Type u_2
inst✝⁴ : Category.{u_3, u_1} C
inst✝³ : Category.{u_4, u_2} D
G : C ⥤ D
J : GrothendieckTopology C
K : GrothendieckTopology D
A : Type w
inst✝² : Category.{w', w} A
inst✝¹ : ∀ (X : Dᵒᵖ), Limits.HasLimitsOfShape (StructuredArrow X G.op) A
inst✝ : IsDenseSubsite J K G
Y : Sheaf J A
U : C
X : A
f : (yoneda.obj (((𝟭 (Cᵒᵖ ⥤ A)).obj Y.val).obj (op U))).obj (op X)
l : (X Y Z : C) → (f : X ⟶ Y) → (g : G.obj Y ⟶ G.obj Z) → (G.imageSieve g).arrows f → (X ⟶ Z)
hl :
  ∀ (X Y Z : C) (f : X ⟶ Y) (g : G.obj Y ⟶ G.obj Z) (hf : (G.imageSieve g).arrows f),
    G.map (l X Y Z f g hf) = G.map f ≫ g
g : StructuredArrow (op (G.obj U)) G.op
I₁ I₂ : GrothendieckTopology.Cover.Arrow ⟨G.imageSieve g.hom.unop, ⋯⟩
r : I₁.Relation I₂
V : C
iUV : V ⟶ r.Z
hiUV : iUV ≫ r.g₁ ≫ l I₁.Y (unop g.2) U I₁.f g.hom.unop ⋯ = iUV ≫ r.g₂ ≫ l I₂.Y (unop g.2) U I₂.f g.hom.unop ⋯
⊢ (Y.val ⋙ coyoneda.obj (op X)).map iUV.op
      ((fun I => f ≫ Y.val.map (l I.Y (unop g.2) U I.f g.hom.unop ⋯).op) I₁ ≫ Y.val.map r.g₁.op) =
    (Y.val ⋙ coyoneda.obj (op X)).map iUV.op
      ((fun I => f ≫ Y.val.map (l I.Y (unop g.2) U I.f g.hom.unop ⋯).op) I₂ ≫ Y.val.map r.g₂.op)

Tactic:
simp [← map_comp, ← op_comp, hiUV]

Result:
no goals