l3lab/ntp-mathlib huggingface dataset:
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        

Proof state:
case mpr.transitive.refine_1
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
t₁ t₂ : P.obj (Opposite.op Y)
h₁ : FamilyOfElements.IsAmalgamation x t₁
h₂ : FamilyOfElements.IsAmalgamation x t₂
⊢ t₁ = t₂

Next tactic:
refine (H1 f).ext (fun Z g hg => ?_)
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        refine (H1 f).ext (fun Z g hg => ?_)
        

Proof state:
case mpr.transitive.refine_1
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
t₁ t₂ : P.obj (Opposite.op Y)
h₁ : FamilyOfElements.IsAmalgamation x t₁
h₂ : FamilyOfElements.IsAmalgamation x t₂
Z : C
g : Z ⟶ Y
hg : (Sieve.pullback f R).arrows g
⊢ P.map g.op t₁ = P.map g.op t₂

Next tactic:
refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        refine (H1 f).ext (fun Z g hg => ?_)
        refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
        

Proof state:
case mpr.transitive.refine_1
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
t₁ t₂ : P.obj (Opposite.op Y)
h₁ : FamilyOfElements.IsAmalgamation x t₁
h₂ : FamilyOfElements.IsAmalgamation x t₂
Z : C
g : Z ⟶ Y
hg : (Sieve.pullback f R).arrows g
ZZ : C
gg : ZZ ⟶ Z
hgg : (Sieve.pullback (𝟙 Z) (Sieve.pullback (g ≫ f) S)).arrows gg
⊢ P.map gg.op (P.map g.op t₁) = P.map gg.op (P.map g.op t₂)

Next tactic:
simp only [Sieve.pullback_id, Sieve.pullback_apply] at hgg
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        refine (H1 f).ext (fun Z g hg => ?_)
        refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
        simp only [Sieve.pullback_id, Sieve.pullback_apply] at hgg
        

Proof state:
case mpr.transitive.refine_1
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
t₁ t₂ : P.obj (Opposite.op Y)
h₁ : FamilyOfElements.IsAmalgamation x t₁
h₂ : FamilyOfElements.IsAmalgamation x t₂
Z : C
g : Z ⟶ Y
hg : (Sieve.pullback f R).arrows g
ZZ : C
gg : ZZ ⟶ Z
hgg : S.arrows (gg ≫ g ≫ f)
⊢ P.map gg.op (P.map g.op t₁) = P.map gg.op (P.map g.op t₂)

Next tactic:
simp only [← types_comp_apply]
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        refine (H1 f).ext (fun Z g hg => ?_)
        refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
        simp only [Sieve.pullback_id, Sieve.pullback_apply] at hgg
        simp only [← types_comp_apply]
        

Proof state:
case mpr.transitive.refine_1
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
t₁ t₂ : P.obj (Opposite.op Y)
h₁ : FamilyOfElements.IsAmalgamation x t₁
h₂ : FamilyOfElements.IsAmalgamation x t₂
Z : C
g : Z ⟶ Y
hg : (Sieve.pullback f R).arrows g
ZZ : C
gg : ZZ ⟶ Z
hgg : S.arrows (gg ≫ g ≫ f)
⊢ (P.map g.op ≫ P.map gg.op) t₁ = (P.map g.op ≫ P.map gg.op) t₂

Next tactic:
rw [← P.map_comp, ← op_comp, h₁, h₂]
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        refine (H1 f).ext (fun Z g hg => ?_)
        refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
        simp only [Sieve.pullback_id, Sieve.pullback_apply] at hgg
        simp only [← types_comp_apply]
        rw [← P.map_comp, ← op_comp, h₁, h₂]
        

Proof state:
case mpr.transitive.refine_1.h
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
t₁ t₂ : P.obj (Opposite.op Y)
h₁ : FamilyOfElements.IsAmalgamation x t₁
h₂ : FamilyOfElements.IsAmalgamation x t₂
Z : C
g : Z ⟶ Y
hg : (Sieve.pullback f R).arrows g
ZZ : C
gg : ZZ ⟶ Z
hgg : S.arrows (gg ≫ g ≫ f)
⊢ (Sieve.pullback f S).arrows (gg ≫ g)

Next tactic:
simpa only [Sieve.pullback_apply, Category.assoc] using hgg
/--
The main theorem of this file: Given a coverage `K` on `C`,
a `Type*`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
the associated Grothendieck topology.
-/
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    Presieve.IsSheaf (toGrothendieck _ K) P ↔
    (∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
  constructor
  · intro H X R hR
    rw [Presieve.isSheafFor_iff_generate]
    apply H _ <| saturate.of _ _ hR
  · intro H X S hS
    -- This is the key point of the proof:
    -- We must generalize the induction in the correct way.
    suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
      simpa using this (f := 𝟙 _)
    induction hS with
    | of X S hS =>
      intro Y f
      obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
      apply Presieve.isSheafFor_of_factorsThru (S := T)
      · intro Z g hg
        obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
        exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
      · apply H; assumption
      · intro Z g _
        obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
        refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
    | top => intros; simpa using Presieve.isSheafFor_top_sieve _
    | transitive X R S _ _ H1 H2 =>
      intro Y f
      simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
      choose H1 H1' using H1
      choose H2 H2' using H2
      refine ⟨?_, fun x hx => ?_⟩
      · intro x t₁ t₂ h₁ h₂
        refine (H1 f).ext (fun Z g hg => ?_)
        refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
        simp only [Sieve.pullback_id, Sieve.pullback_apply] at hgg
        simp only [← types_comp_apply]
        rw [← P.map_comp, ← op_comp, h₁, h₂]
        simpa only [Sieve.pullback_apply, Category.assoc] using hgg
      

Proof state:
case mpr.transitive.refine_2
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
P : Cᵒᵖ ⥤ Type w
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝¹ : saturate K X R
a✝ : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
Y : C
f : Y ⟶ X
H :
  ∀ {X : C},
    ∀ R ∈ covering K X,
      IsSeparatedFor P R ∧
        ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSeparatedFor P (Sieve.pullback f R).arrows
H1' :
  ∀ ⦃Y : C⦄ (f : Y ⟶ X) (x : FamilyOfElements P (Sieve.pullback f R).arrows),
    FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
H2 :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), IsSeparatedFor P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows
H2' :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f →
      ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y) (x : FamilyOfElements P (Sieve.pullback f_1 (Sieve.pullback f S)).arrows),
        FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t
x : FamilyOfElements P (Sieve.pullback f S).arrows
hx : FamilyOfElements.Compatible x
⊢ ∃ t, FamilyOfElements.IsAmalgamation x t

Next tactic:
let y : ∀ ⦃Z : C⦄ (g : Z ⟶ Y),
        ((S.pullback (g ≫ f)).pullback (𝟙 _)).arrows.FamilyOfElements P :=
        fun Z g ZZ gg hgg => x (gg ≫ g) (by simpa using hgg)
/--
A presheaf is a sheaf for the Grothendieck topology generated by a union of coverages iff it is a
sheaf for the Grothendieck topology generated by each coverage separately.
-/
theorem isSheaf_sup (K L : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    (Presieve.IsSheaf ((K ⊔ L).toGrothendieck C)) P ↔
    (Presieve.IsSheaf (K.toGrothendieck C)) P ∧ (Presieve.IsSheaf (L.toGrothendieck C)) P := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K L : Coverage C
P : Cᵒᵖ ⥤ Type w
⊢ IsSheaf (toGrothendieck C (K ⊔ L)) P ↔ IsSheaf (toGrothendieck C K) P ∧ IsSheaf (toGrothendieck C L) P

Next tactic:
refine ⟨fun h ↦ ⟨Presieve.isSheaf_of_le _ ((gi C).gc.monotone_l le_sup_left) h,
      Presieve.isSheaf_of_le _ ((gi C).gc.monotone_l le_sup_right) h⟩, fun h ↦ ?_⟩
/--
A presheaf is a sheaf for the Grothendieck topology generated by a union of coverages iff it is a
sheaf for the Grothendieck topology generated by each coverage separately.
-/
theorem isSheaf_sup (K L : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    (Presieve.IsSheaf ((K ⊔ L).toGrothendieck C)) P ↔
    (Presieve.IsSheaf (K.toGrothendieck C)) P ∧ (Presieve.IsSheaf (L.toGrothendieck C)) P := by
  refine ⟨fun h ↦ ⟨Presieve.isSheaf_of_le _ ((gi C).gc.monotone_l le_sup_left) h,
      Presieve.isSheaf_of_le _ ((gi C).gc.monotone_l le_sup_right) h⟩, fun h ↦ ?_⟩
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K L : Coverage C
P : Cᵒᵖ ⥤ Type w
h : IsSheaf (toGrothendieck C K) P ∧ IsSheaf (toGrothendieck C L) P
⊢ IsSheaf (toGrothendieck C (K ⊔ L)) P

Next tactic:
rw [isSheaf_coverage, isSheaf_coverage] at h
/--
A presheaf is a sheaf for the Grothendieck topology generated by a union of coverages iff it is a
sheaf for the Grothendieck topology generated by each coverage separately.
-/
theorem isSheaf_sup (K L : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
    (Presieve.IsSheaf ((K ⊔ L).toGrothendieck C)) P ↔
    (Presieve.IsSheaf (K.toGrothendieck C)) P ∧ (Presieve.IsSheaf (L.toGrothendieck C)) P := by
  refine ⟨fun h ↦ ⟨Presieve.isSheaf_of_le _ ((gi C).gc.monotone_l le_sup_left) h,
      Presieve.isSheaf_of_le _ ((gi C).gc.monotone_l le_sup_right) h⟩, fun h ↦ ?_⟩
  rw [isSheaf_coverage, isSheaf_coverage] at h
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K L : Coverage C
P : Cᵒᵖ ⥤ Type w
h : (∀ {X : C}, ∀ R ∈ covering K X, IsSheafFor P R) ∧ ∀ {X : C}, ∀ R ∈ covering L X, IsSheafFor P R
⊢ IsSheaf (toGrothendieck C (K ⊔ L)) P

Next tactic:
rw [isSheaf_coverage]