Theorem: CategoryTheory.Presheaf.isSheaf_iff_multifork
File: Mathlib/CategoryTheory/Sites/Sheaf.lean

tactic: refine' ⟨fun hP X S => ⟨isLimitOfIsSheaf _ _ _ hP⟩, _⟩
state_before: C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
⊢ IsSheaf J P ↔
    ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))

tactic: intro h E X S hS x hx
state_before: C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
⊢ (∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))) →
    IsSheaf J P

tactic: let T : J.Cover X := ⟨S, hS⟩
state_before: C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t

tactic: obtain ⟨hh⟩ := h _ T
state_before: C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t

tactic: let K : Multifork (T.index P) := Multifork.ofι _ E (fun I => x I.f I.hf) fun I => hx _ _ _ _ I.w
state_before: case intro
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t

tactic: use hh.lift K
state_before: case intro
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ ∃! t, Presieve.FamilyOfElements.IsAmalgamation x t

tactic: dsimp
state_before: case intro
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ (fun t => Presieve.FamilyOfElements.IsAmalgamation x t) (IsLimit.lift hh K) ∧
    ∀ (y : (P ⋙ coyoneda.obj E.op).obj X.op),
      (fun t => Presieve.FamilyOfElements.IsAmalgamation x t) y → y = IsLimit.lift hh K

tactic: constructor
state_before: case intro
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ Presieve.FamilyOfElements.IsAmalgamation x
      (IsLimit.lift hh
        (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
          (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
          (_ :
            ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
              (P ⋙ coyoneda.obj E.op).map I.g₁.op
                  (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f)) =
                (P ⋙ coyoneda.obj E.op).map I.g₂.op
                  (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f))))) ∧
    ∀ (y : E ⟶ P.obj X.op),
      Presieve.FamilyOfElements.IsAmalgamation x y →
        y =
          IsLimit.lift hh
            (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
              (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
              (_ :
                ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
                  (P ⋙ coyoneda.obj E.op).map I.g₁.op
                      (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                        (_ :
                          (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                            (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                                I).f)) =
                    (P ⋙ coyoneda.obj E.op).map I.g₂.op
                      (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                        (_ :
                          (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                            (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                                I).f))))

tactic: intro Y f hf
state_before: case intro.left
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ Presieve.FamilyOfElements.IsAmalgamation x
    (IsLimit.lift hh
      (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
        (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
        (_ :
          ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
            (P ⋙ coyoneda.obj E.op).map I.g₁.op
                (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f)) =
              (P ⋙ coyoneda.obj E.op).map I.g₂.op
                (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                          I).f)))))

tactic: apply hh.fac K (WalkingMulticospan.left ⟨Y, f, hf⟩)
state_before: case intro.left
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
Y : C
f : Y ⟶ X
hf : S.arrows f
⊢ (P ⋙ coyoneda.obj E.op).map f.op
      (IsLimit.lift hh
        (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
          (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
          (_ :
            ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
              (P ⋙ coyoneda.obj E.op).map I.g₁.op
                  (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f)) =
                (P ⋙ coyoneda.obj E.op).map I.g₂.op
                  (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                    (_ :
                      (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                        (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                            I).f))))) =
    x f hf

tactic: intro e he
state_before: case intro.right
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
⊢ ∀ (y : E ⟶ P.obj X.op),
    Presieve.FamilyOfElements.IsAmalgamation x y →
      y =
        IsLimit.lift hh
          (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
            (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
            (_ :
              ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
                (P ⋙ coyoneda.obj E.op).map I.g₁.op
                    (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                      (_ :
                        (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                          (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                              I).f)) =
                  (P ⋙ coyoneda.obj E.op).map I.g₂.op
                    (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                      (_ :
                        (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                          (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P)
                              I).f))))

tactic: apply hh.uniq K
state_before: case intro.right
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj X.op
he : Presieve.FamilyOfElements.IsAmalgamation x e
⊢ e =
    IsLimit.lift hh
      (Multifork.ofι (GrothendieckTopology.Cover.index { val := S, property := hS } P) E
        (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows I.f))
        (_ :
          ∀ (I : (GrothendieckTopology.Cover.index { val := S, property := hS } P).R),
            (P ⋙ coyoneda.obj E.op).map I.g₁.op
                (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f)) =
              (P ⋙ coyoneda.obj E.op).map I.g₂.op
                (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f
                  (_ :
                    (GrothendieckTopology.Cover.sieve { val := S, property := hS }).arrows
                      (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index { val := S, property := hS } P) I).f))))

tactic: rintro (a | b)
state_before: case intro.right.x
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj X.op
he : Presieve.FamilyOfElements.IsAmalgamation x e
⊢ ∀ (j : WalkingMulticospan (GrothendieckTopology.Cover.index T P).fstTo (GrothendieckTopology.Cover.index T P).sndTo),
    e ≫ (GrothendieckTopology.Cover.multifork T P).π.app j = K.π.app j

tactic: apply he
state_before: case intro.right.x.left
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj X.op
he : Presieve.FamilyOfElements.IsAmalgamation x e
a : (GrothendieckTopology.Cover.index T P).L
⊢ e ≫ (GrothendieckTopology.Cover.multifork T P).π.app (WalkingMulticospan.left a) = K.π.app (WalkingMulticospan.left a)

tactic: rw [← K.w (WalkingMulticospan.Hom.fst b), ←
  (T.multifork P).w (WalkingMulticospan.Hom.fst b), ← assoc]
state_before: case intro.right.x.right
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj X.op
he : Presieve.FamilyOfElements.IsAmalgamation x e
b : (GrothendieckTopology.Cover.index T P).R
⊢ e ≫ (GrothendieckTopology.Cover.multifork T P).π.app (WalkingMulticospan.right b) =
    K.π.app (WalkingMulticospan.right b)

tactic: congr 1
state_before: case intro.right.x.right
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj X.op
he : Presieve.FamilyOfElements.IsAmalgamation x e
b : (GrothendieckTopology.Cover.index T P).R
⊢ (e ≫
        (GrothendieckTopology.Cover.multifork T P).π.app
          (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b))) ≫
      (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index T P)).map (WalkingMulticospan.Hom.fst b) =
    K.π.app (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b)) ≫
      (MulticospanIndex.multicospan (GrothendieckTopology.Cover.index T P)).map (WalkingMulticospan.Hom.fst b)

tactic: apply he
state_before: case intro.right.x.right.e_a
C : Type u₁
inst✝¹ : Category C
A : Type u₂
inst✝ : Category A
J : GrothendieckTopology C
U : C
R : Presieve U
P : Cᵒᵖ ⥤ A
h : ∀ (X : C) (S : GrothendieckTopology.Cover J X), Nonempty (IsLimit (GrothendieckTopology.Cover.multifork S P))
E : A
X : C
S : Sieve X
hS : S ∈ GrothendieckTopology.sieves J X
x : Presieve.FamilyOfElements (P ⋙ coyoneda.obj E.op) S.arrows
hx : Presieve.FamilyOfElements.Compatible x
T : GrothendieckTopology.Cover J X := { val := S, property := hS }
hh : IsLimit (GrothendieckTopology.Cover.multifork T P)
K : Multifork (GrothendieckTopology.Cover.index T P) :=
  Multifork.ofι (GrothendieckTopology.Cover.index T P) E
    (fun I => x I.f (_ : (GrothendieckTopology.Cover.sieve T).arrows I.f))
    (_ :
      ∀ (I : (GrothendieckTopology.Cover.index T P).R),
        (P ⋙ coyoneda.obj E.op).map I.g₁.op
            (x (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) I).f)) =
          (P ⋙ coyoneda.obj E.op).map I.g₂.op
            (x (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f
              (_ :
                (GrothendieckTopology.Cover.sieve T).arrows
                  (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index T P) I).f)))
e : E ⟶ P.obj X.op
he : Presieve.FamilyOfElements.IsAmalgamation x e
b : (GrothendieckTopology.Cover.index T P).R
⊢ e ≫
      (GrothendieckTopology.Cover.multifork T P).π.app
        (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b)) =
    K.π.app (WalkingMulticospan.left (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index T P) b))