l3lab/ntp-mathlib huggingface dataset:
lemma saturate_of_superset (K : Coverage C) {X : C} {S T : Sieve X} (h : S ≤ T)
    (hS : saturate K X S) : saturate K X T := by
  apply saturate.transitive _ _ _ hS
  intro Y g hg
  rw [eq_top_pullback (h := h)]
  · apply saturate.top
  · 

Proof state:
case hf
C : Type u_1
inst✝ : Category.{u_2, u_1} C
K : Coverage C
X : C
S T : Sieve X
h : S ≤ T
hS : saturate K X S
Y : C
g : Y ⟶ X
hg : S.arrows g
⊢ S.arrows g

Next tactic:
assumption
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    

Proof state:
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
⊢ ∀ ⦃X Y : C⦄ ⦃S : Sieve X⦄ (f : Y ⟶ X), S ∈ saturate K X → Sieve.pullback f S ∈ saturate K Y

Next tactic:
intro X Y S f hS
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    

Proof state:
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X Y : C
S : Sieve X
f : Y ⟶ X
hS : S ∈ saturate K X
⊢ Sieve.pullback f S ∈ saturate K Y

Next tactic:
induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    | top X => apply saturate.top
    | transitive X R S _ hS H1 _ =>
      apply saturate.transitive
      apply H1 f
      intro Z g hg
      rw [← Sieve.pullback_comp]
      exact hS hg
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    

Proof state:
case of
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
⊢ Sieve.pullback f (Sieve.generate S) ∈ saturate K Y

Next tactic:
| of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      

Proof state:
case of
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
⊢ Sieve.pullback f (Sieve.generate S) ∈ saturate K Y

Next tactic:
obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      

Proof state:
case of.intro.intro
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
R : Presieve Y
hR1 : R ∈ covering K Y
hR2 : Presieve.FactorsThruAlong R S f
⊢ Sieve.pullback f (Sieve.generate S) ∈ saturate K Y

Next tactic:
suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      

Proof state:
case of.intro.intro
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
R : Presieve Y
hR1 : R ∈ covering K Y
hR2 : Presieve.FactorsThruAlong R S f
⊢ Sieve.generate R ≤ Sieve.pullback f (Sieve.generate S)

Next tactic:
rintro Z g ⟨W, i, e, h1, h2⟩
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      

Proof state:
case of.intro.intro.intro.intro.intro.intro
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
R : Presieve Y
hR1 : R ∈ covering K Y
hR2 : Presieve.FactorsThruAlong R S f
Z : C
g : Z ⟶ Y
W : C
i : Z ⟶ W
e : W ⟶ Y
h1 : R e
h2 : i ≫ e = g
⊢ (Sieve.pullback f (Sieve.generate S)).arrows g

Next tactic:
obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      

Proof state:
case of.intro.intro.intro.intro.intro.intro.intro.intro.intro.intro
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
R : Presieve Y
hR1 : R ∈ covering K Y
hR2 : Presieve.FactorsThruAlong R S f
Z : C
g : Z ⟶ Y
W : C
i : Z ⟶ W
e : W ⟶ Y
h1 : R e
h2 : i ≫ e = g
WW : C
ii : W ⟶ WW
ee : WW ⟶ X
hh1 : S ee
hh2 : ii ≫ ee = e ≫ f
⊢ (Sieve.pullback f (Sieve.generate S)).arrows g

Next tactic:
refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      

Proof state:
case of.intro.intro.intro.intro.intro.intro.intro.intro.intro.intro
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
S : Presieve X
hS : S ∈ covering K X
Y : C
f : Y ⟶ X
R : Presieve Y
hR1 : R ∈ covering K Y
hR2 : Presieve.FactorsThruAlong R S f
Z : C
g : Z ⟶ Y
W : C
i : Z ⟶ W
e : W ⟶ Y
h1 : R e
h2 : i ≫ e = g
WW : C
ii : W ⟶ WW
ee : WW ⟶ X
hh1 : S ee
hh2 : ii ≫ ee = e ≫ f
⊢ (i ≫ ii) ≫ ee = g ≫ f

Next tactic:
simp only [hh2, reassoc_of% h2, Category.assoc]
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    

Proof state:
case top
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S : Sieve X✝
X Y : C
f : Y ⟶ X
⊢ Sieve.pullback f ⊤ ∈ saturate K Y

Next tactic:
| top X => apply saturate.top
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    | top X => 

Proof state:
case top
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S : Sieve X✝
X Y : C
f : Y ⟶ X
⊢ Sieve.pullback f ⊤ ∈ saturate K Y

Next tactic:
apply saturate.top
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    | top X => apply saturate.top
    

Proof state:
case transitive
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝ : saturate K X R
hS : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), Sieve.pullback f R ∈ saturate K Y
a_ih✝ :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), Sieve.pullback f_1 (Sieve.pullback f S) ∈ saturate K Y_1
Y : C
f : Y ⟶ X
⊢ Sieve.pullback f S ∈ saturate K Y

Next tactic:
| transitive X R S _ hS H1 _ =>
      apply saturate.transitive
      apply H1 f
      intro Z g hg
      rw [← Sieve.pullback_comp]
      exact hS hg
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    | top X => apply saturate.top
    | transitive X R S _ hS H1 _ =>
      

Proof state:
case transitive
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝ : saturate K X R
hS : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), Sieve.pullback f R ∈ saturate K Y
a_ih✝ :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), Sieve.pullback f_1 (Sieve.pullback f S) ∈ saturate K Y_1
Y : C
f : Y ⟶ X
⊢ Sieve.pullback f S ∈ saturate K Y

Next tactic:
apply saturate.transitive
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    | top X => apply saturate.top
    | transitive X R S _ hS H1 _ =>
      apply saturate.transitive
      

Proof state:
case transitive.a
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝ : saturate K X R
hS : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), Sieve.pullback f R ∈ saturate K Y
a_ih✝ :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), Sieve.pullback f_1 (Sieve.pullback f S) ∈ saturate K Y_1
Y : C
f : Y ⟶ X
⊢ saturate K Y ?transitive.R
case transitive.a
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝ : saturate K X R
hS : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), Sieve.pullback f R ∈ saturate K Y
a_ih✝ :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), Sieve.pullback f_1 (Sieve.pullback f S) ∈ saturate K Y_1
Y : C
f : Y ⟶ X
⊢ ∀ ⦃Y_1 : C⦄ ⦃f_1 : Y_1 ⟶ Y⦄, ?transitive.R.arrows f_1 → saturate K Y_1 (Sieve.pullback f_1 (Sieve.pullback f S))
case transitive.R
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝ : saturate K X R
hS : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), Sieve.pullback f R ∈ saturate K Y
a_ih✝ :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), Sieve.pullback f_1 (Sieve.pullback f S) ∈ saturate K Y_1
Y : C
f : Y ⟶ X
⊢ Sieve Y

Next tactic:
apply H1 f
variable (C) in
/--
The Grothendieck topology associated to a coverage `K`.
It is defined *inductively* as follows:
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
  sieve for the associated Grothendieck topology.
2. The top sieves are in the associated Grothendieck topology.
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.

The pullback compatibility condition for a coverage ensures that the
associated Grothendieck topology is pullback stable, and so an additional constructor
in the inductive construction is not needed.
-/
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
  sieves := saturate K
  top_mem' := .top
  pullback_stable' := by
    intro X Y S f hS
    induction hS generalizing Y with
    | of X S hS =>
      obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
      suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
        saturate_of_superset _ this (saturate.of _ _ hR1)
      rintro Z g ⟨W, i, e, h1, h2⟩
      obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
      refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
      simp only [hh2, reassoc_of% h2, Category.assoc]
    | top X => apply saturate.top
    | transitive X R S _ hS H1 _ =>
      apply saturate.transitive
      apply H1 f
      

Proof state:
case transitive.a
C : Type ?u.27900
inst✝ : Category.{?u.27904, ?u.27900} C
K : Coverage C
X✝ : C
S✝ : Sieve X✝
X : C
R S : Sieve X
a✝ : saturate K X R
hS : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R.arrows f → saturate K Y (Sieve.pullback f S)
H1 : ∀ ⦃Y : C⦄ (f : Y ⟶ X), Sieve.pullback f R ∈ saturate K Y
a_ih✝ :
  ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄,
    R.arrows f → ∀ ⦃Y_1 : C⦄ (f_1 : Y_1 ⟶ Y), Sieve.pullback f_1 (Sieve.pullback f S) ∈ saturate K Y_1
Y : C
f : Y ⟶ X
⊢ ∀ ⦃Y_1 : C⦄ ⦃f_1 : Y_1 ⟶ Y⦄,
    (Sieve.pullback f R).arrows f_1 → saturate K Y_1 (Sieve.pullback f_1 (Sieve.pullback f S))

Next tactic:
intro Z g hg