l3lab/ntp-mathlib huggingface dataset:
/-- If `P` is a sheaf for `S`, and it is iso to `P'`, then `P'` is a sheaf for `S`. This shows that
"being a sheaf for a presieve" is a mathematical or hygienic property.
-/
theorem isSheafFor_iso {P' : Cᵒᵖ ⥤ Type w} (i : P ≅ P') : IsSheafFor P R → IsSheafFor P' R := by
  intro h x hx
  let x' := x.compPresheafMap i.inv
  have : x'.Compatible := FamilyOfElements.Compatible.compPresheafMap i.inv hx
  obtain ⟨t, ht1, ht2⟩ := h x' this
  use i.hom.app _ t
  fconstructor
  · convert FamilyOfElements.IsAmalgamation.compPresheafMap i.hom ht1
    simp
  · intro y hy
    

Proof state:
case h.right
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
P' : Cᵒᵖ ⥤ Type w
i : P ≅ P'
h : IsSheafFor P R
x : FamilyOfElements P' R
hx : FamilyOfElements.Compatible x
x' : FamilyOfElements P R := FamilyOfElements.compPresheafMap i.inv x
this : FamilyOfElements.Compatible x'
t : P.obj (op X)
ht1 : FamilyOfElements.IsAmalgamation x' t
ht2 : ∀ (y : P.obj (op X)), (fun t => FamilyOfElements.IsAmalgamation x' t) y → y = t
y : P'.obj (op X)
hy : FamilyOfElements.IsAmalgamation x y
⊢ y = i.hom.app (op X) t

Next tactic:
rw [show y = (i.inv.app (op X) ≫ i.hom.app (op X)) y by simp]
/-- If `P` is a sheaf for `S`, and it is iso to `P'`, then `P'` is a sheaf for `S`. This shows that
"being a sheaf for a presieve" is a mathematical or hygienic property.
-/
theorem isSheafFor_iso {P' : Cᵒᵖ ⥤ Type w} (i : P ≅ P') : IsSheafFor P R → IsSheafFor P' R := by
  intro h x hx
  let x' := x.compPresheafMap i.inv
  have : x'.Compatible := FamilyOfElements.Compatible.compPresheafMap i.inv hx
  obtain ⟨t, ht1, ht2⟩ := h x' this
  use i.hom.app _ t
  fconstructor
  · convert FamilyOfElements.IsAmalgamation.compPresheafMap i.hom ht1
    simp
  · intro y hy
    rw [show y = (i.inv.app (op X) ≫ i.hom.app (op X)) y by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
P' : Cᵒᵖ ⥤ Type w
i : P ≅ P'
h : IsSheafFor P R
x : FamilyOfElements P' R
hx : FamilyOfElements.Compatible x
x' : FamilyOfElements P R := FamilyOfElements.compPresheafMap i.inv x
this : FamilyOfElements.Compatible x'
t : P.obj (op X)
ht1 : FamilyOfElements.IsAmalgamation x' t
ht2 : ∀ (y : P.obj (op X)), (fun t => FamilyOfElements.IsAmalgamation x' t) y → y = t
y : P'.obj (op X)
hy : FamilyOfElements.IsAmalgamation x y
⊢ y = (i.inv.app (op X) ≫ i.hom.app (op X)) y

Next tactic:
simp
/-- If `P` is a sheaf for `S`, and it is iso to `P'`, then `P'` is a sheaf for `S`. This shows that
"being a sheaf for a presieve" is a mathematical or hygienic property.
-/
theorem isSheafFor_iso {P' : Cᵒᵖ ⥤ Type w} (i : P ≅ P') : IsSheafFor P R → IsSheafFor P' R := by
  intro h x hx
  let x' := x.compPresheafMap i.inv
  have : x'.Compatible := FamilyOfElements.Compatible.compPresheafMap i.inv hx
  obtain ⟨t, ht1, ht2⟩ := h x' this
  use i.hom.app _ t
  fconstructor
  · convert FamilyOfElements.IsAmalgamation.compPresheafMap i.hom ht1
    simp
  · intro y hy
    rw [show y = (i.inv.app (op X) ≫ i.hom.app (op X)) y by simp]
    

Proof state:
case h.right
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
P' : Cᵒᵖ ⥤ Type w
i : P ≅ P'
h : IsSheafFor P R
x : FamilyOfElements P' R
hx : FamilyOfElements.Compatible x
x' : FamilyOfElements P R := FamilyOfElements.compPresheafMap i.inv x
this : FamilyOfElements.Compatible x'
t : P.obj (op X)
ht1 : FamilyOfElements.IsAmalgamation x' t
ht2 : ∀ (y : P.obj (op X)), (fun t => FamilyOfElements.IsAmalgamation x' t) y → y = t
y : P'.obj (op X)
hy : FamilyOfElements.IsAmalgamation x y
⊢ (i.inv.app (op X) ≫ i.hom.app (op X)) y = i.hom.app (op X) t

Next tactic:
simp [ht2 (i.inv.app _ y) (FamilyOfElements.IsAmalgamation.compPresheafMap i.inv hy)]
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
⊢ IsSheafFor P R

Next tactic:
rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
⊢ IsSeparatedFor P R ∧
    ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t

Next tactic:
constructor
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · 

Proof state:
case left
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
⊢ IsSeparatedFor P R

Next tactic:
intro x t₁ t₂ ht₁ ht₂
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    

Proof state:
case left
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
t₁ t₂ : P.obj (op X)
ht₁ : FamilyOfElements.IsAmalgamation x t₁
ht₂ : FamilyOfElements.IsAmalgamation x t₂
⊢ t₁ = t₂

Next tactic:
exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · 

Proof state:
case right
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
⊢ ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t

Next tactic:
intro x hx
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · intro x hx
    

Proof state:
case right
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
hx : FamilyOfElements.Compatible x
⊢ ∃ t, FamilyOfElements.IsAmalgamation x t

Next tactic:
use hS.amalgamate _ (hx.restrict h)
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · intro x hx
    use hS.amalgamate _ (hx.restrict h)
    

Proof state:
case h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
hx : FamilyOfElements.Compatible x
⊢ FamilyOfElements.IsAmalgamation x
    (IsSheafFor.amalgamate hS (FamilyOfElements.restrict h x)
      (_ : FamilyOfElements.Compatible (FamilyOfElements.restrict h x)))

Next tactic:
intro W j hj
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · intro x hx
    use hS.amalgamate _ (hx.restrict h)
    intro W j hj
    

Proof state:
case h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
hx : FamilyOfElements.Compatible x
W : C
j : W ⟶ X
hj : R j
⊢ P.map j.op
      (IsSheafFor.amalgamate hS (FamilyOfElements.restrict h x)
        (_ : FamilyOfElements.Compatible (FamilyOfElements.restrict h x))) =
    x j hj

Next tactic:
apply (trans hj).ext
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · intro x hx
    use hS.amalgamate _ (hx.restrict h)
    intro W j hj
    apply (trans hj).ext
    

Proof state:
case h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
hx : FamilyOfElements.Compatible x
W : C
j : W ⟶ X
hj : R j
⊢ ∀ ⦃Y : C⦄ ⦃f : Y ⟶ W⦄,
    (Sieve.pullback j S).arrows f →
      P.map f.op
          (P.map j.op
            (IsSheafFor.amalgamate hS (FamilyOfElements.restrict h x)
              (_ : FamilyOfElements.Compatible (FamilyOfElements.restrict h x)))) =
        P.map f.op (x j hj)

Next tactic:
intro Y f hf
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · intro x hx
    use hS.amalgamate _ (hx.restrict h)
    intro W j hj
    apply (trans hj).ext
    intro Y f hf
    

Proof state:
case h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y✝ : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
hx : FamilyOfElements.Compatible x
W : C
j : W ⟶ X
hj : R j
Y : C
f : Y ⟶ W
hf : (Sieve.pullback j S).arrows f
⊢ P.map f.op
      (P.map j.op
        (IsSheafFor.amalgamate hS (FamilyOfElements.restrict h x)
          (_ : FamilyOfElements.Compatible (FamilyOfElements.restrict h x)))) =
    P.map f.op (x j hj)

Next tactic:
rw [← FunctorToTypes.map_comp_apply, ← op_comp, hS.valid_glue (hx.restrict h) _ hf,
      FamilyOfElements.restrict, ← hx (𝟙 _) f (h _ hf) _ (id_comp _)]
/-- If a presieve `R` on `X` has a subsieve `S` such that:

* `P` is a sheaf for `S`.
* For every `f` in `R`, `P` is separated for the pullback of `S` along `f`,

then `P` is a sheaf for `R`.

This is closely related to [Elephant] C2.1.6(i).
-/
theorem isSheafFor_subsieve_aux (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (hS : IsSheafFor P (S : Presieve X))
    (trans : ∀ ⦃Y⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R := by
  rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
  constructor
  · intro x t₁ t₂ ht₁ ht₂
    exact
      hS.isSeparatedFor _ _ _ (isAmalgamation_restrict h x t₁ ht₁)
        (isAmalgamation_restrict h x t₂ ht₂)
  · intro x hx
    use hS.amalgamate _ (hx.restrict h)
    intro W j hj
    apply (trans hj).ext
    intro Y f hf
    rw [← FunctorToTypes.map_comp_apply, ← op_comp, hS.valid_glue (hx.restrict h) _ hf,
      FamilyOfElements.restrict, ← hx (𝟙 _) f (h _ hf) _ (id_comp _)]
    

Proof state:
case h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y✝ : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
hS : IsSheafFor P S.arrows
trans : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → IsSeparatedFor P (Sieve.pullback f S).arrows
x : FamilyOfElements P R
hx : FamilyOfElements.Compatible x
W : C
j : W ⟶ X
hj : R j
Y : C
f : Y ⟶ W
hf : (Sieve.pullback j S).arrows f
⊢ x (f ≫ j) (_ : f ≫ j ∈ R) = P.map (𝟙 Y).op (x (f ≫ j) (_ : f ≫ j ∈ R))

Next tactic:
simp
/--
If `P` is a sheaf for every pullback of the sieve `S`, then `P` is a sheaf for any presieve which
contains `S`.
This is closely related to [Elephant] C2.1.6.
-/
theorem isSheafFor_subsieve (P : Cᵒᵖ ⥤ Type w) {S : Sieve X} {R : Presieve X}
    (h : (S : Presieve X) ≤ R) (trans : ∀ ⦃Y⦄ (f : Y ⟶ X),
      IsSheafFor P (S.pullback f : Presieve Y)) :
    IsSheafFor P R :=
  isSheafFor_subsieve_aux P h (by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P✝ Q U : Cᵒᵖ ⥤ Type w
X Y : C
S✝ : Sieve X
R✝ : Presieve X
P : Cᵒᵖ ⥤ Type w
S : Sieve X
R : Presieve X
h : S.arrows ≤ R
trans : ∀ ⦃Y : C⦄ (f : Y ⟶ X), IsSheafFor P (Sieve.pullback f S).arrows
⊢ IsSheafFor P S.arrows

Next tactic:
simpa using trans (𝟙 _)
theorem exists_familyOfElements :
    ∃ (x' : FamilyOfElements P (ofArrows X π)), ∀ (i : I), x' _ (ofArrows.mk i) = x i := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
x : (i : I) → P.obj (op (X i))
hx : Compatible P π x
⊢ ∃ x', ∀ (i : I), x' (π i) (_ : ofArrows X π (π i)) = x i

Next tactic:
choose i h h' using @ofArrows_surj _ _ _ _ _ π
theorem exists_familyOfElements :
    ∃ (x' : FamilyOfElements P (ofArrows X π)), ∀ (i : I), x' _ (ofArrows.mk i) = x i := by
  choose i h h' using @ofArrows_surj _ _ _ _ _ π
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
x : (i : I) → P.obj (op (X i))
hx : Compatible P π x
i : {Z : C} → (g : Z ⟶ B) → ofArrows (fun i => X i) π g → I
h : ∀ {Z : C} (g : Z ⟶ B) (hg : ofArrows (fun i => X i) π g), X (i g hg) = Z
h' : ∀ {Z : C} (g : Z ⟶ B) (hg : ofArrows (fun i => X i) π g), g = eqToHom (_ : Z = X (i g hg)) ≫ π (i g hg)
⊢ ∃ x', ∀ (i : I), x' (π i) (_ : ofArrows X π (π i)) = x i

Next tactic:
exact ⟨fun Y f hf ↦ P.map (eqToHom (h f hf).symm).op (x _),
    fun j ↦ (hx _ j (X j) _ (𝟙 _) <| by rw [← h', id_comp]).trans <| by simp⟩
theorem exists_familyOfElements :
    ∃ (x' : FamilyOfElements P (ofArrows X π)), ∀ (i : I), x' _ (ofArrows.mk i) = x i := by
  choose i h h' using @ofArrows_surj _ _ _ _ _ π
  exact ⟨fun Y f hf ↦ P.map (eqToHom (h f hf).symm).op (x _),
    fun j ↦ (hx _ j (X j) _ (𝟙 _) <| by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
x : (i : I) → P.obj (op (X i))
hx : Compatible P π x
i : {Z : C} → (g : Z ⟶ B) → ofArrows (fun i => X i) π g → I
h : ∀ {Z : C} (g : Z ⟶ B) (hg : ofArrows (fun i => X i) π g), X (i g hg) = Z
h' : ∀ {Z : C} (g : Z ⟶ B) (hg : ofArrows (fun i => X i) π g), g = eqToHom (_ : Z = X (i g hg)) ≫ π (i g hg)
j : I
⊢ eqToHom (_ : X j = X (i (π j) (_ : ofArrows X π (π j)))) ≫ π (i (π j) (_ : ofArrows X π (π j))) = 𝟙 (X j) ≫ π j

Next tactic:
rw [← h', id_comp]
theorem exists_familyOfElements :
    ∃ (x' : FamilyOfElements P (ofArrows X π)), ∀ (i : I), x' _ (ofArrows.mk i) = x i := by
  choose i h h' using @ofArrows_surj _ _ _ _ _ π
  exact ⟨fun Y f hf ↦ P.map (eqToHom (h f hf).symm).op (x _),
    fun j ↦ (hx _ j (X j) _ (𝟙 _) <| by rw [← h', id_comp]).trans <| by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
x : (i : I) → P.obj (op (X i))
hx : Compatible P π x
i : {Z : C} → (g : Z ⟶ B) → ofArrows (fun i => X i) π g → I
h : ∀ {Z : C} (g : Z ⟶ B) (hg : ofArrows (fun i => X i) π g), X (i g hg) = Z
h' : ∀ {Z : C} (g : Z ⟶ B) (hg : ofArrows (fun i => X i) π g), g = eqToHom (_ : Z = X (i g hg)) ≫ π (i g hg)
j : I
⊢ P.map (𝟙 (X j)).op (x j) = x j

Next tactic:
simp
theorem familyOfElements_compatible : hx.familyOfElements.Compatible := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
x : (i : I) → P.obj (op (X i))
hx : Compatible P π x
⊢ FamilyOfElements.Compatible (familyOfElements hx)

Next tactic:
rintro Y₁ Y₂ Z g₁ g₂ f₁ f₂ ⟨i⟩ ⟨j⟩ hgf
theorem familyOfElements_compatible : hx.familyOfElements.Compatible := by
  rintro Y₁ Y₂ Z g₁ g₂ f₁ f₂ ⟨i⟩ ⟨j⟩ hgf
  

Proof state:
case mk.mk
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y✝¹ : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
x : (i : I) → P.obj (op (X i))
hx : Compatible P π x
Z Y✝ : C
i : I
g₁ : Z ⟶ X i
Y : C
j : I
g₂ : Z ⟶ X j
hgf : g₁ ≫ π i = g₂ ≫ π j
⊢ P.map g₁.op (familyOfElements hx (π i) (_ : ofArrows (fun i => X i) π (π i))) =
    P.map g₂.op (familyOfElements hx (π j) (_ : ofArrows (fun i => X i) π (π j)))

Next tactic:
simp [hx i j Z g₁ g₂ hgf]
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
⊢ IsSheafFor P (ofArrows X π) ↔
    ∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x → ∃! t, ∀ (i : I), P.map (π i).op t = x i

Next tactic:
refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
  · 

Proof state:
case refine_1
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
h : IsSheafFor P (ofArrows X π)
x : (i : I) → P.obj (op (X i))
hx : Arrows.Compatible P π x
⊢ ∃! t, ∀ (i : I), P.map (π i).op t = x i

Next tactic:
obtain ⟨t, ht₁, ht₂⟩ := h _ hx.familyOfElements_compatible
theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔
    (∀ (x : (i : I) → P.obj (op (X i))), Arrows.Compatible P π x →
    ∃! t, ∀ i, P.map (π i).op t = x i) := by
  refine ⟨fun h x hx ↦ ?_, fun h x hx ↦ ?_⟩
  · obtain ⟨t, ht₁, ht₂⟩ := h _ hx.familyOfElements_compatible
    

Proof state:
case refine_1.intro.intro
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X✝ Y : C
S : Sieve X✝
R : Presieve X✝
B : C
I : Type u_1
X : I → C
π : (i : I) → X i ⟶ B
h : IsSheafFor P (ofArrows X π)
x : (i : I) → P.obj (op (X i))
hx : Arrows.Compatible P π x
t : P.obj (op B)
ht₁ : FamilyOfElements.IsAmalgamation (Arrows.Compatible.familyOfElements hx) t
ht₂ :
  ∀ (y : P.obj (op B)), (fun t => FamilyOfElements.IsAmalgamation (Arrows.Compatible.familyOfElements hx) t) y → y = t
⊢ ∃! t, ∀ (i : I), P.map (π i).op t = x i

Next tactic:
refine ⟨t, fun i ↦ ?_, fun t' ht' ↦ ht₂ _ fun _ _ ⟨i⟩ ↦ ?_⟩