-- Mathlib/CategoryTheory/Sites/DenseSubsite/Basic.lean
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible

Proof state:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
Z : D
W₁ W₂ : C
iWX₁ : G.obj W₁ ⟶ X
iWX₂ : G.obj W₂ ⟶ X
iZW₁ : Z ⟶ G.obj W₁
iZW₂ : Z ⟶ G.obj W₂
e : iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂
V : C
iVZ : G.obj V ⟶ Z
⊢ ℱ'.val.map iVZ.op (ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x))) =
    ℱ'.val.map iVZ.op (ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x)))

Tactic:
simp only [← op_comp, ← FunctorToTypes.map_comp_apply, ← Functor.map_comp, naturality_apply,
  Category.assoc, e]

Result:
no goals

Proof state:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
Y₁ Y₂ Z : D
iZY₁ : Z ⟶ Y₁
iZY₂ : Z ⟶ Y₂
W₁ : C
iYW₁ : Y₁ ⟶ G.obj W₁
iWX₁ : G.obj W₁ ⟶ X
h₁ : coverByImage G X (iYW₁ ≫ iWX₁)
W₂ : C
iYW₂ : Y₂ ⟶ G.obj W₂
iWX₂ : G.obj W₂ ⟶ X
h₂ : coverByImage G X (iYW₂ ≫ iWX₂)
e : iZY₁ ≫ iYW₁ ≫ iWX₁ = iZY₂ ≫ iYW₂ ≫ iWX₂
⊢ (iZY₁ ≫ { obj := W₁, lift := iYW₁, map := iWX₁, fac := ⋯ }.lift) ≫
      { obj := W₁, lift := iYW₁, map := iWX₁, fac := ⋯ }.map =
    (iZY₂ ≫ { obj := W₂, lift := iYW₂, map := iWX₂, fac := ⋯ }.lift) ≫
      { obj := W₂, lift := iYW₂, map := iWX₂, fac := ⋯ }.map

Tactic:
simpa only [Category.assoc] using e

Result:
no goals

Proof state:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
⊢ (pushforwardFamily α x).Compatible

Tactic:
rintro Y₁ Y₂ Z iZY₁ iZY₂ f₁ f₂ h₁ h₂ e

Result:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
Y₁ Y₂ Z : D
iZY₁ : Z ⟶ Y₁
iZY₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : iZY₁ ≫ f₁ = iZY₂ ≫ f₂
⊢ ℱ'.val.map iZY₁.op (pushforwardFamily α x f₁ h₁) = ℱ'.val.map iZY₂.op (pushforwardFamily α x f₂ h₂)

Proof state:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
Y₁ Y₂ Z : D
iZY₁ : Z ⟶ Y₁
iZY₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : iZY₁ ≫ f₁ = iZY₂ ≫ f₂
⊢ ℱ'.val.map (iZY₁ ≫ (Nonempty.some h₁).lift).op (α.app (op (Nonempty.some h₁).1) (ℱ.map (Nonempty.some h₁).map.op x)) =
    ℱ'.val.map (iZY₂ ≫ (Nonempty.some h₂).lift).op (α.app (op (Nonempty.some h₂).1) (ℱ.map (Nonempty.some h₂).map.op x))

Tactic:
generalize Nonempty.some h₁ = l₁

Result:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
Y₁ Y₂ Z : D
iZY₁ : Z ⟶ Y₁
iZY₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : iZY₁ ≫ f₁ = iZY₂ ≫ f₂
l₁ : CoverByImageStructure G f₁
⊢ ℱ'.val.map (iZY₁ ≫ l₁.lift).op (α.app (op l₁.1) (ℱ.map l₁.map.op x)) =
    ℱ'.val.map (iZY₂ ≫ (Nonempty.some h₂).lift).op (α.app (op (Nonempty.some h₂).1) (ℱ.map (Nonempty.some h₂).map.op x))

Proof state:
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
Y₁ Y₂ Z : D
iZY₁ : Z ⟶ Y₁
iZY₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : iZY₁ ≫ f₁ = iZY₂ ≫ f₂
l₁ : CoverByImageStructure G f₁
l₂ : CoverByImageStructure G f₂
⊢ ℱ'.val.map (iZY₁ ≫ l₁.lift).op (α.app (op l₁.1) (ℱ.map l₁.map.op x)) =
    ℱ'.val.map (iZY₂ ≫ l₂.lift).op (α.app (op l₂.1) (ℱ.map l₂.map.op x))

Tactic:
obtain ⟨W₁, iYW₁, iWX₁, rfl⟩ := l₁

Result:
case mk
C : Type u_1
inst✝³ : Category.{u_6, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
K : GrothendieckTopology D
G : C ⥤ D
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : Sheaf K (Type v)
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
inst✝¹ : G.IsCoverDense K
inst✝ : G.IsLocallyFull K
X : D
x : ℱ.obj (op X)
this :
  ∀ {Z : D} {W₁ W₂ : C} (iWX₁ : G.obj W₁ ⟶ X) (iWX₂ : G.obj W₂ ⟶ X) (iZW₁ : Z ⟶ G.obj W₁) (iZW₂ : Z ⟶ G.obj W₂),
    iZW₁ ≫ iWX₁ = iZW₂ ≫ iWX₂ →
      ℱ'.val.map iZW₁.op (α.app (op W₁) (ℱ.map iWX₁.op x)) = ℱ'.val.map iZW₂.op (α.app (op W₂) (ℱ.map iWX₂.op x))
Y₁ Y₂ Z : D
iZY₁ : Z ⟶ Y₁
iZY₂ : Z ⟶ Y₂
f₂ : Y₂ ⟶ X
h₂ : coverByImage G X f₂
l₂ : CoverByImageStructure G f₂
W₁ : C
iYW₁ : Y₁ ⟶ G.obj W₁
iWX₁ : G.obj W₁ ⟶ X
h₁ : coverByImage G X (iYW₁ ≫ iWX₁)
e : iZY₁ ≫ iYW₁ ≫ iWX₁ = iZY₂ ≫ f₂
⊢ ℱ'.val.map (iZY₁ ≫ { obj := W₁, lift := iYW₁, map := iWX₁, fac := ⋯ }.lift).op
      (α.app (op { obj := W₁, lift := iYW₁, map := iWX₁, fac := ⋯ }.1)
        (ℱ.map { obj := W₁, lift := iYW₁, map := iWX₁, fac := ⋯ }.map.op x)) =
    ℱ'.val.map (iZY₂ ≫ l₂.lift).op (α.app (op l₂.1) (ℱ.map l₂.map.op x))