l3lab/ntp-mathlib huggingface dataset:
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P R) :
    ((firstObjEqFamily P R).hom x).Compatible ↔ firstMap P R x = secondMap P R x := by
  rw [Presieve.pullbackCompatible_iff]
  constructor
  · intro t
    apply Limits.Types.limit_ext
    rintro ⟨⟨Y, f, hf⟩, Z, g, hg⟩
    simpa [firstMap, secondMap] using t hf hg
  · 

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : FirstObj P R
⊢ firstMap P R x = secondMap P R x → Presieve.FamilyOfElements.PullbackCompatible ((firstObjEqFamily P R).hom x)

Next tactic:
intro t Y Z f g hf hg
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P R) :
    ((firstObjEqFamily P R).hom x).Compatible ↔ firstMap P R x = secondMap P R x := by
  rw [Presieve.pullbackCompatible_iff]
  constructor
  · intro t
    apply Limits.Types.limit_ext
    rintro ⟨⟨Y, f, hf⟩, Z, g, hg⟩
    simpa [firstMap, secondMap] using t hf hg
  · intro t Y Z f g hf hg
    

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : FirstObj P R
t : firstMap P R x = secondMap P R x
Y Z : C
f : Y ⟶ X
g : Z ⟶ X
hf : R f
hg : R g
⊢ P.map pullback.fst.op ((firstObjEqFamily P R).hom x f hf) = P.map pullback.snd.op ((firstObjEqFamily P R).hom x g hg)

Next tactic:
rw [Types.limit_ext_iff'] at t
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P R) :
    ((firstObjEqFamily P R).hom x).Compatible ↔ firstMap P R x = secondMap P R x := by
  rw [Presieve.pullbackCompatible_iff]
  constructor
  · intro t
    apply Limits.Types.limit_ext
    rintro ⟨⟨Y, f, hf⟩, Z, g, hg⟩
    simpa [firstMap, secondMap] using t hf hg
  · intro t Y Z f g hf hg
    rw [Types.limit_ext_iff'] at t
    

Proof state:
case mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : FirstObj P R
t :
  ∀ (j : Discrete (((Y : C) × { f // R f }) × (Z : C) × { g // R g })),
    limit.π (Discrete.functor fun fg => P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd))) j (firstMap P R x) =
      limit.π (Discrete.functor fun fg => P.obj (op (Limits.pullback ↑fg.1.snd ↑fg.2.snd))) j (secondMap P R x)
Y Z : C
f : Y ⟶ X
g : Z ⟶ X
hf : R f
hg : R g
⊢ P.map pullback.fst.op ((firstObjEqFamily P R).hom x f hf) = P.map pullback.snd.op ((firstObjEqFamily P R).hom x g hg)

Next tactic:
simpa [firstMap, secondMap] using t ⟨⟨⟨Y, f, hf⟩, Z, g, hg⟩⟩
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
⊢ Presieve.IsSheafFor P R ↔
    Nonempty (IsLimit (Fork.ofι (forkMap P R) (_ : forkMap P R ≫ firstMap P R = forkMap P R ≫ secondMap P R)))

Next tactic:
rw [Types.type_equalizer_iff_unique]
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
⊢ Presieve.IsSheafFor P R ↔ ∀ (y : FirstObj P R), firstMap P R y = secondMap P R y → ∃! x, forkMap P R x = y

Next tactic:
erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
⊢ Presieve.IsSheafFor P R ↔
    ∀ (x : Presieve.FamilyOfElements P R),
      firstMap P R ((firstObjEqFamily P R).symm x) = secondMap P R ((firstObjEqFamily P R).symm x) →
        ∃! x_1, forkMap P R x_1 = (firstObjEqFamily P R).symm x

Next tactic:
simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
⊢ Presieve.IsSheafFor P R ↔
    ∀ (x : Presieve.FamilyOfElements P R),
      Presieve.FamilyOfElements.Compatible x → ∃! x_1, forkMap P R x_1 = (firstObjEqFamily P R).symm x

Next tactic:
apply ball_congr
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  

Proof state:
case H
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
⊢ ∀ (x : Presieve.FamilyOfElements P R),
    Presieve.FamilyOfElements.Compatible x →
      ((∃! t, Presieve.FamilyOfElements.IsAmalgamation x t) ↔ ∃! x_1, forkMap P R x_1 = (firstObjEqFamily P R).symm x)

Next tactic:
intro x _
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  

Proof state:
case H
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
⊢ (∃! t, Presieve.FamilyOfElements.IsAmalgamation x t) ↔ ∃! x_1, forkMap P R x_1 = (firstObjEqFamily P R).symm x

Next tactic:
apply exists_unique_congr
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  

Proof state:
case H.h
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
⊢ ∀ (a : P.obj (op X)), Presieve.FamilyOfElements.IsAmalgamation x a ↔ forkMap P R a = (firstObjEqFamily P R).symm x

Next tactic:
intro t
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  

Proof state:
case H.h
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
⊢ Presieve.FamilyOfElements.IsAmalgamation x t ↔ forkMap P R t = (firstObjEqFamily P R).symm x

Next tactic:
rw [Equiv.eq_symm_apply]
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  

Proof state:
case H.h
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
⊢ Presieve.FamilyOfElements.IsAmalgamation x t ↔ (firstObjEqFamily P R).toEquiv (forkMap P R t) = x

Next tactic:
constructor
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  constructor
  · 

Proof state:
case H.h.mp
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
⊢ Presieve.FamilyOfElements.IsAmalgamation x t → (firstObjEqFamily P R).toEquiv (forkMap P R t) = x

Next tactic:
intro q
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  constructor
  · intro q
    

Proof state:
case H.h.mp
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
q : Presieve.FamilyOfElements.IsAmalgamation x t
⊢ (firstObjEqFamily P R).toEquiv (forkMap P R t) = x

Next tactic:
funext Y f hf
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  constructor
  · intro q
    funext Y f hf
    

Proof state:
case H.h.mp.h.h.h
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
q : Presieve.FamilyOfElements.IsAmalgamation x t
Y : C
f : Y ⟶ X
hf : R f
⊢ (firstObjEqFamily P R).toEquiv (forkMap P R t) f hf = x f hf

Next tactic:
simpa [forkMap] using q _ _
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  constructor
  · intro q
    funext Y f hf
    simpa [forkMap] using q _ _
  · 

Proof state:
case H.h.mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
⊢ (firstObjEqFamily P R).toEquiv (forkMap P R t) = x → Presieve.FamilyOfElements.IsAmalgamation x t

Next tactic:
intro q Y f hf
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  constructor
  · intro q
    funext Y f hf
    simpa [forkMap] using q _ _
  · intro q Y f hf
    

Proof state:
case H.h.mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
q : (firstObjEqFamily P R).toEquiv (forkMap P R t) = x
Y : C
f : Y ⟶ X
hf : R f
⊢ P.map f.op t = x f hf

Next tactic:
rw [← q]
/-- `P` is a sheaf for `R`, iff the fork given by `w` is an equalizer.
See <https://stacks.math.columbia.edu/tag/00VM>.
-/
theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by
  rw [Types.type_equalizer_iff_unique]
  erw [← Equiv.forall_congr_left (firstObjEqFamily P R).toEquiv.symm]
  simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply]
  apply ball_congr
  intro x _
  apply exists_unique_congr
  intro t
  rw [Equiv.eq_symm_apply]
  constructor
  · intro q
    funext Y f hf
    simpa [forkMap] using q _ _
  · intro q Y f hf
    rw [← q]
    

Proof state:
case H.h.mpr
C : Type u
inst✝¹ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X : C
R : Presieve X
S : Sieve X
inst✝ : Presieve.hasPullbacks R
x : Presieve.FamilyOfElements P R
h✝ : Presieve.FamilyOfElements.Compatible x
t : P.obj (op X)
q : (firstObjEqFamily P R).toEquiv (forkMap P R t) = x
Y : C
f : Y ⟶ X
hf : R f
⊢ P.map f.op t = (firstObjEqFamily P R).toEquiv (forkMap P R t) f hf

Next tactic:
simp [forkMap]
@[ext]
lemma FirstObj.ext (z₁ z₂ : FirstObj P X) (h : ∀ i, (Pi.π _ i : FirstObj P X ⟶ _) z₁ =
    (Pi.π _ i : FirstObj P X ⟶ _) z₂) : z₁ = z₂ := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
z₁ z₂ : FirstObj P X
h : ∀ (i : I), Pi.π (fun i => P.obj (op (X i))) i z₁ = Pi.π (fun i => P.obj (op (X i))) i z₂
⊢ z₁ = z₂

Next tactic:
apply Limits.Types.limit_ext
@[ext]
lemma FirstObj.ext (z₁ z₂ : FirstObj P X) (h : ∀ i, (Pi.π _ i : FirstObj P X ⟶ _) z₁ =
    (Pi.π _ i : FirstObj P X ⟶ _) z₂) : z₁ = z₂ := by
  apply Limits.Types.limit_ext
  

Proof state:
case w
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
z₁ z₂ : FirstObj P X
h : ∀ (i : I), Pi.π (fun i => P.obj (op (X i))) i z₁ = Pi.π (fun i => P.obj (op (X i))) i z₂
⊢ ∀ (j : Discrete I),
    limit.π (Discrete.functor fun i => P.obj (op (X i))) j z₁ =
      limit.π (Discrete.functor fun i => P.obj (op (X i))) j z₂

Next tactic:
rintro ⟨i⟩
@[ext]
lemma FirstObj.ext (z₁ z₂ : FirstObj P X) (h : ∀ i, (Pi.π _ i : FirstObj P X ⟶ _) z₁ =
    (Pi.π _ i : FirstObj P X ⟶ _) z₂) : z₁ = z₂ := by
  apply Limits.Types.limit_ext
  rintro ⟨i⟩
  

Proof state:
case w.mk
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
z₁ z₂ : FirstObj P X
h : ∀ (i : I), Pi.π (fun i => P.obj (op (X i))) i z₁ = Pi.π (fun i => P.obj (op (X i))) i z₂
i : I
⊢ limit.π (Discrete.functor fun i => P.obj (op (X i))) { as := i } z₁ =
    limit.π (Discrete.functor fun i => P.obj (op (X i))) { as := i } z₂

Next tactic:
exact h i
@[ext]
lemma SecondObj.ext (z₁ z₂ : SecondObj P X π) (h : ∀ ij, (Pi.π _ ij : SecondObj P X π ⟶ _) z₁ =
    (Pi.π _ ij : SecondObj P X π ⟶ _) z₂) : z₁ = z₂ := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
z₁ z₂ : SecondObj P X π
h :
  ∀ (ij : I × I),
    Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij z₁ =
      Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij z₂
⊢ z₁ = z₂

Next tactic:
apply Limits.Types.limit_ext
@[ext]
lemma SecondObj.ext (z₁ z₂ : SecondObj P X π) (h : ∀ ij, (Pi.π _ ij : SecondObj P X π ⟶ _) z₁ =
    (Pi.π _ ij : SecondObj P X π ⟶ _) z₂) : z₁ = z₂ := by
  apply Limits.Types.limit_ext
  

Proof state:
case w
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
z₁ z₂ : SecondObj P X π
h :
  ∀ (ij : I × I),
    Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij z₁ =
      Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij z₂
⊢ ∀ (j : Discrete (I × I)),
    limit.π (Discrete.functor fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) j z₁ =
      limit.π (Discrete.functor fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) j z₂

Next tactic:
rintro ⟨i⟩
@[ext]
lemma SecondObj.ext (z₁ z₂ : SecondObj P X π) (h : ∀ ij, (Pi.π _ ij : SecondObj P X π ⟶ _) z₁ =
    (Pi.π _ ij : SecondObj P X π ⟶ _) z₂) : z₁ = z₂ := by
  apply Limits.Types.limit_ext
  rintro ⟨i⟩
  

Proof state:
case w.mk
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
z₁ z₂ : SecondObj P X π
h :
  ∀ (ij : I × I),
    Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij z₁ =
      Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij z₂
i : I × I
⊢ limit.π (Discrete.functor fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) { as := i } z₁ =
    limit.π (Discrete.functor fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) { as := i } z₂

Next tactic:
exact h i
theorem w : forkMap P X π ≫ firstMap P X π = forkMap P X π ≫ secondMap P X π := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
⊢ forkMap P X π ≫ firstMap P X π = forkMap P X π ≫ secondMap P X π

Next tactic:
ext x ij
theorem w : forkMap P X π ≫ firstMap P X π = forkMap P X π ≫ secondMap P X π := by
  ext x ij
  

Proof state:
case h.h
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
x : P.obj (op B)
ij : I × I
⊢ Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij ((forkMap P X π ≫ firstMap P X π) x) =
    Pi.π (fun ij => P.obj (op (Limits.pullback (π ij.1) (π ij.2)))) ij ((forkMap P X π ≫ secondMap P X π) x)

Next tactic:
simp only [firstMap, secondMap, forkMap, types_comp_apply, Types.pi_lift_π_apply,
    ← FunctorToTypes.map_comp_apply, ← op_comp, pullback.condition]
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P X) : (Arrows.Compatible P π ((Types.productIso _).hom x)) ↔
    firstMap P X π x = secondMap P X π x := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
x : FirstObj P X
⊢ Arrows.Compatible P π ((Types.productIso fun i => P.obj (op (X i))).hom x) ↔ firstMap P X π x = secondMap P X π x

Next tactic:
rw [Arrows.pullbackCompatible_iff]
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P X) : (Arrows.Compatible P π ((Types.productIso _).hom x)) ↔
    firstMap P X π x = secondMap P X π x := by
  rw [Arrows.pullbackCompatible_iff]
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
x : FirstObj P X
⊢ Arrows.PullbackCompatible P π ((Types.productIso fun i => P.obj (op (X i))).hom x) ↔
    firstMap P X π x = secondMap P X π x

Next tactic:
constructor
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P X) : (Arrows.Compatible P π ((Types.productIso _).hom x)) ↔
    firstMap P X π x = secondMap P X π x := by
  rw [Arrows.pullbackCompatible_iff]
  constructor
  · 

Proof state:
case mp
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
x : FirstObj P X
⊢ Arrows.PullbackCompatible P π ((Types.productIso fun i => P.obj (op (X i))).hom x) →
    firstMap P X π x = secondMap P X π x

Next tactic:
intro t
/--
The family of elements given by `x : FirstObj P S` is compatible iff `firstMap` and `secondMap`
map it to the same point.
-/
theorem compatible_iff (x : FirstObj P X) : (Arrows.Compatible P π ((Types.productIso _).hom x)) ↔
    firstMap P X π x = secondMap P X π x := by
  rw [Arrows.pullbackCompatible_iff]
  constructor
  · intro t
    

Proof state:
case mp
C : Type u
inst✝³ : Category.{v, u} C
P : Cᵒᵖ ⥤ Type (max v u)
X✝ : C
R : Presieve X✝
S : Sieve X✝
inst✝² : hasPullbacks R
B : C
I : Type
X : I → C
π : (i : I) → X i ⟶ B
inst✝¹ : UnivLE.{w, max v u}
inst✝ : hasPullbacks (ofArrows X π)
x : FirstObj P X
t : Arrows.PullbackCompatible P π ((Types.productIso fun i => P.obj (op (X i))).hom x)
⊢ firstMap P X π x = secondMap P X π x

Next tactic:
ext ij