l3lab/ntp-mathlib huggingface dataset:
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    

Proof state:
case mp
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 v₁
g : yoneda.obj X ⟶ P
Y : C
f : Y ⟶ X
hf : S.arrows f
⊢ P.map f.op (yonedaEquiv g) = (functorInclusion S ≫ g).app (op Y) { val := f, property := hf }

Next tactic:
rw [yonedaEquiv_naturality]
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    

Proof state:
case mp
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 v₁
g : yoneda.obj X ⟶ P
Y : C
f : Y ⟶ X
hf : S.arrows f
⊢ yonedaEquiv (yoneda.map f ≫ g) = (functorInclusion S ≫ g).app (op Y) { val := f, property := hf }

Next tactic:
dsimp
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    dsimp
    

Proof state:
case mp
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 v₁
g : yoneda.obj X ⟶ P
Y : C
f : Y ⟶ X
hf : S.arrows f
⊢ g.app (op Y) (𝟙 Y ≫ f) = g.app (op Y) f

Next tactic:
simp
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    dsimp
    simp
  -- See note [dsimp, simp].
  · 

Proof state:
case mpr
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 v₁
x : functor S ⟶ P
g : yoneda.obj X ⟶ P
⊢ (∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S.arrows f), P.map f.op (yonedaEquiv g) = x.app (op Y) { val := f, property := h }) →
    functorInclusion S ≫ g = x

Next tactic:
intro h
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    dsimp
    simp
  -- See note [dsimp, simp].
  · intro h
    

Proof state:
case mpr
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 v₁
x : functor S ⟶ P
g : yoneda.obj X ⟶ P
h : ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S.arrows f), P.map f.op (yonedaEquiv g) = x.app (op Y) { val := f, property := h }
⊢ functorInclusion S ≫ g = x

Next tactic:
ext Y ⟨f, hf⟩
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    dsimp
    simp
  -- See note [dsimp, simp].
  · intro h
    ext Y ⟨f, hf⟩
    

Proof state:
case mpr.w.h.h.mk
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 v₁
x : functor S ⟶ P
g : yoneda.obj X ⟶ P
h : ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S.arrows f), P.map f.op (yonedaEquiv g) = x.app (op Y) { val := f, property := h }
Y : Cᵒᵖ
f : Y.unop ⟶ X
hf : S.arrows f
⊢ (functorInclusion S ≫ g).app Y { val := f, property := hf } = x.app Y { val := f, property := hf }

Next tactic:
convert h f hf
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    dsimp
    simp
  -- See note [dsimp, simp].
  · intro h
    ext Y ⟨f, hf⟩
    convert h f hf
    

Proof state:
case h.e'_2.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 v₁
x : functor S ⟶ P
g : yoneda.obj X ⟶ P
h : ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S.arrows f), P.map f.op (yonedaEquiv g) = x.app (op Y) { val := f, property := h }
Y : Cᵒᵖ
f : Y.unop ⟶ X
hf : S.arrows f
e_1✝ : P.obj Y = P.obj (op Y.unop)
⊢ (functorInclusion S ≫ g).app Y { val := f, property := hf } = P.map f.op (yonedaEquiv g)

Next tactic:
rw [yonedaEquiv_naturality]
/-- (Implementation). A lemma useful to prove `isSheafFor_iff_yonedaSheafCondition`. -/
theorem extension_iff_amalgamation {P : Cᵒᵖ ⥤ Type v₁} (x : S.functor ⟶ P) (g : yoneda.obj X ⟶ P) :
    S.functorInclusion ≫ g = x ↔
      (natTransEquivCompatibleFamily x).1.IsAmalgamation (yonedaEquiv g) := by
  change _ ↔ ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S f), P.map f.op (yonedaEquiv g) = x.app (op Y) ⟨f, h⟩
  constructor
  · rintro rfl Y f hf
    rw [yonedaEquiv_naturality]
    dsimp
    simp
  -- See note [dsimp, simp].
  · intro h
    ext Y ⟨f, hf⟩
    convert h f hf
    rw [yonedaEquiv_naturality]
    

Proof state:
case h.e'_2.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 v₁
x : functor S ⟶ P
g : yoneda.obj X ⟶ P
h : ∀ ⦃Y : C⦄ (f : Y ⟶ X) (h : S.arrows f), P.map f.op (yonedaEquiv g) = x.app (op Y) { val := f, property := h }
Y : Cᵒᵖ
f : Y.unop ⟶ X
hf : S.arrows f
e_1✝ : P.obj Y = P.obj (op Y.unop)
⊢ (functorInclusion S ≫ g).app Y { val := f, property := hf } = yonedaEquiv (yoneda.map f ≫ g)

Next tactic:
simp [yonedaEquiv]
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := 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 v₁
⊢ IsSheafFor P S.arrows ↔ YonedaSheafCondition P S

Next tactic:
rw [IsSheafFor, YonedaSheafCondition]
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  

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 v₁
⊢ (∀ (x : FamilyOfElements P S.arrows), FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t) ↔
    ∀ (f : functor S ⟶ P), ∃! g, functorInclusion S ≫ g = f

Next tactic:
simp_rw [extension_iff_amalgamation]
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  simp_rw [extension_iff_amalgamation]
  

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 v₁
⊢ (∀ (x : FamilyOfElements P S.arrows), FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t) ↔
    ∀ (f : functor S ⟶ P), ∃! g, FamilyOfElements.IsAmalgamation (↑(natTransEquivCompatibleFamily f)) (yonedaEquiv g)

Next tactic:
rw [Equiv.forall_congr_left' natTransEquivCompatibleFamily]
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  simp_rw [extension_iff_amalgamation]
  rw [Equiv.forall_congr_left' natTransEquivCompatibleFamily]
  

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 v₁
⊢ (∀ (x : FamilyOfElements P S.arrows), FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t) ↔
    ∀ (y : { x // FamilyOfElements.Compatible x }),
      ∃! g,
        FamilyOfElements.IsAmalgamation (↑(natTransEquivCompatibleFamily (natTransEquivCompatibleFamily.symm y)))
          (yonedaEquiv g)

Next tactic:
rw [Subtype.forall]
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  simp_rw [extension_iff_amalgamation]
  rw [Equiv.forall_congr_left' natTransEquivCompatibleFamily]
  rw [Subtype.forall]
  

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 v₁
⊢ (∀ (x : FamilyOfElements P S.arrows), FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t) ↔
    ∀ (a : FamilyOfElements P S.arrows) (b : FamilyOfElements.Compatible a),
      ∃! g,
        FamilyOfElements.IsAmalgamation
          (↑(natTransEquivCompatibleFamily (natTransEquivCompatibleFamily.symm { val := a, property := b })))
          (yonedaEquiv g)

Next tactic:
apply ball_congr
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  simp_rw [extension_iff_amalgamation]
  rw [Equiv.forall_congr_left' natTransEquivCompatibleFamily]
  rw [Subtype.forall]
  apply ball_congr
  

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 v₁
⊢ ∀ (x : FamilyOfElements P S.arrows) (h : FamilyOfElements.Compatible x),
    (∃! t, FamilyOfElements.IsAmalgamation x t) ↔
      ∃! g,
        FamilyOfElements.IsAmalgamation
          (↑(natTransEquivCompatibleFamily (natTransEquivCompatibleFamily.symm { val := x, property := h })))
          (yonedaEquiv g)

Next tactic:
intro x hx
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  simp_rw [extension_iff_amalgamation]
  rw [Equiv.forall_congr_left' natTransEquivCompatibleFamily]
  rw [Subtype.forall]
  apply ball_congr
  intro x hx
  

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 v₁
x : FamilyOfElements P S.arrows
hx : FamilyOfElements.Compatible x
⊢ (∃! t, FamilyOfElements.IsAmalgamation x t) ↔
    ∃! g,
      FamilyOfElements.IsAmalgamation
        (↑(natTransEquivCompatibleFamily (natTransEquivCompatibleFamily.symm { val := x, property := hx })))
        (yonedaEquiv g)

Next tactic:
rw [Equiv.exists_unique_congr_left _]
/-- The yoneda version of the sheaf condition is equivalent to the sheaf condition.

C2.1.4 of [Elephant].
-/
theorem isSheafFor_iff_yonedaSheafCondition {P : Cᵒᵖ ⥤ Type v₁} :
    IsSheafFor P (S : Presieve X) ↔ YonedaSheafCondition P S := by
  rw [IsSheafFor, YonedaSheafCondition]
  simp_rw [extension_iff_amalgamation]
  rw [Equiv.forall_congr_left' natTransEquivCompatibleFamily]
  rw [Subtype.forall]
  apply ball_congr
  intro x hx
  rw [Equiv.exists_unique_congr_left _]
  

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 v₁
x : FamilyOfElements P S.arrows
hx : FamilyOfElements.Compatible x
⊢ (∃! t, FamilyOfElements.IsAmalgamation x t) ↔
    ∃! y,
      FamilyOfElements.IsAmalgamation
        (↑(natTransEquivCompatibleFamily (natTransEquivCompatibleFamily.symm { val := x, property := hx }))) y

Next tactic:
simp
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      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
⊢ (IsSeparatedFor P R ∧
      ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t) ↔
    IsSheafFor P R

Next tactic:
rw [IsSeparatedFor, ← forall_and]
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  

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
⊢ (∀ (x : FamilyOfElements P R),
      (∀ (t₁ t₂ : P.obj (op X)),
          FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂) ∧
        (FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t)) ↔
    IsSheafFor P R

Next tactic:
apply forall_congr'
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  

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
⊢ ∀ (a : FamilyOfElements P R),
    (∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation a t₁ → FamilyOfElements.IsAmalgamation a t₂ → t₁ = t₂) ∧
        (FamilyOfElements.Compatible a → ∃ t, FamilyOfElements.IsAmalgamation a t) ↔
      FamilyOfElements.Compatible a → ∃! t, FamilyOfElements.IsAmalgamation a t

Next tactic:
intro x
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  

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
x : FamilyOfElements P R
⊢ (∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂) ∧
      (FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t) ↔
    FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t

Next tactic:
constructor
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · 

Proof state:
case h.mp
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
⊢ (∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂) ∧
      (FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t) →
    FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t

Next tactic:
intro z hx
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · intro z hx
    

Proof state:
case h.mp
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
z :
  (∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂) ∧
    (FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t)
hx : FamilyOfElements.Compatible x
⊢ ∃! t, FamilyOfElements.IsAmalgamation x t

Next tactic:
exact exists_unique_of_exists_of_unique (z.2 hx) z.1
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · intro z hx
    exact exists_unique_of_exists_of_unique (z.2 hx) z.1
  · 

Proof state:
case h.mpr
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
⊢ (FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t) →
    (∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂) ∧
      (FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t)

Next tactic:
intro h
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · intro z hx
    exact exists_unique_of_exists_of_unique (z.2 hx) z.1
  · intro h
    

Proof state:
case h.mpr
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
h : FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t
⊢ (∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂) ∧
    (FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t)

Next tactic:
refine' ⟨_, ExistsUnique.exists ∘ h⟩
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · intro z hx
    exact exists_unique_of_exists_of_unique (z.2 hx) z.1
  · intro h
    refine' ⟨_, ExistsUnique.exists ∘ h⟩
    

Proof state:
case h.mpr
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
h : FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t
⊢ ∀ (t₁ t₂ : P.obj (op X)), FamilyOfElements.IsAmalgamation x t₁ → FamilyOfElements.IsAmalgamation x t₂ → t₁ = t₂

Next tactic:
intro t₁ t₂ ht₁ ht₂
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · intro z hx
    exact exists_unique_of_exists_of_unique (z.2 hx) z.1
  · intro h
    refine' ⟨_, ExistsUnique.exists ∘ h⟩
    intro t₁ t₂ ht₁ ht₂
    

Proof state:
case h.mpr
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
h : FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t
t₁ t₂ : P.obj (op X)
ht₁ : FamilyOfElements.IsAmalgamation x t₁
ht₂ : FamilyOfElements.IsAmalgamation x t₂
⊢ t₁ = t₂

Next tactic:
apply (h _).unique ht₁ ht₂
/-- `P` is a sheaf for `R` iff it is separated for `R` and there exists an amalgamation. -/
theorem isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor :
    (IsSeparatedFor P R ∧ ∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) ↔
      IsSheafFor P R := by
  rw [IsSeparatedFor, ← forall_and]
  apply forall_congr'
  intro x
  constructor
  · intro z hx
    exact exists_unique_of_exists_of_unique (z.2 hx) z.1
  · intro h
    refine' ⟨_, ExistsUnique.exists ∘ h⟩
    intro t₁ t₂ ht₁ ht₂
    apply (h _).unique ht₁ ht₂
    

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
x : FamilyOfElements P R
h : FamilyOfElements.Compatible x → ∃! t, FamilyOfElements.IsAmalgamation x t
t₁ t₂ : P.obj (op X)
ht₁ : FamilyOfElements.IsAmalgamation x t₁
ht₂ : FamilyOfElements.IsAmalgamation x t₂
⊢ FamilyOfElements.Compatible x

Next tactic:
exact is_compatible_of_exists_amalgamation x ⟨_, ht₂⟩
/-- If `P` is separated for `R` and every family has an amalgamation, then `P` is a sheaf for `R`.
-/
theorem IsSeparatedFor.isSheafFor (t : IsSeparatedFor P R) :
    (∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) → 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
t : IsSeparatedFor P R
⊢ (∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t) →
    IsSheafFor P R

Next tactic:
rw [← isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor]
/-- If `P` is separated for `R` and every family has an amalgamation, then `P` is a sheaf for `R`.
-/
theorem IsSeparatedFor.isSheafFor (t : IsSeparatedFor P R) :
    (∀ x : FamilyOfElements P R, x.Compatible → ∃ t, x.IsAmalgamation t) → 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
t : IsSeparatedFor P R
⊢ (∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t) →
    IsSeparatedFor P R ∧
      ∀ (x : FamilyOfElements P R), FamilyOfElements.Compatible x → ∃ t, FamilyOfElements.IsAmalgamation x t

Next tactic:
exact And.intro t