l3lab/ntp-mathlib huggingface dataset:
private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n
  | 0 => by
    rw [toFunAux_eq, card_eq_zero, eq_empty_iff_forall_not_mem]
    rintro n hn
    rw [mem_filter, ofNat, mem_range] at hn
    exact bot_le.not_lt (show (⟨n, hn.2⟩ : s) < ⊥ from hn.1)
  | n + 1 => by
    have ih : toFunAux (ofNat s n) = n := right_inverse_aux n
    have h₁ : (ofNat s n : ℕ) ∉ (range (ofNat s n)).filter (· ∈ s) := by simp
    have h₂ : (range (succ (ofNat s n))).filter (· ∈ s) =
        insert ↑(ofNat s n) ((range (ofNat s n)).filter (· ∈ s)) := by
      simp only [Finset.ext_iff, mem_insert, mem_range, mem_filter]
      exact fun m =>
        ⟨fun h => by
          simp only [h.2, and_true_iff]
          exact Or.symm (lt_or_eq_of_le ((@lt_succ_iff_le _ _ _ ⟨m, h.2⟩ _).1 h.1)),
         fun h =>
          h.elim (fun h => h.symm ▸ ⟨lt_succ_self _, (ofNat s n).prop⟩) fun h =>
            ⟨h.1.trans (lt_succ_self _), h.2⟩⟩
    

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝¹ : Infinite ↑s
inst✝ : DecidablePred fun x => x ∈ s
n : ℕ
ih : Nat.Subtype.toFunAux (ofNat s n) = n
h₁ : ↑(ofNat s n) ∉ filter (fun x => x ∈ s) (range ↑(ofNat s n))
h₂ :
  filter (fun x => x ∈ s) (range ↑(succ (ofNat s n))) =
    insert (↑(ofNat s n)) (filter (fun x => x ∈ s) (range ↑(ofNat s n)))
⊢ Nat.Subtype.toFunAux (ofNat s (n + 1)) = n + 1

Next tactic:
simp only [toFunAux_eq, ofNat, range_succ] at ih ⊢
private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n
  | 0 => by
    rw [toFunAux_eq, card_eq_zero, eq_empty_iff_forall_not_mem]
    rintro n hn
    rw [mem_filter, ofNat, mem_range] at hn
    exact bot_le.not_lt (show (⟨n, hn.2⟩ : s) < ⊥ from hn.1)
  | n + 1 => by
    have ih : toFunAux (ofNat s n) = n := right_inverse_aux n
    have h₁ : (ofNat s n : ℕ) ∉ (range (ofNat s n)).filter (· ∈ s) := by simp
    have h₂ : (range (succ (ofNat s n))).filter (· ∈ s) =
        insert ↑(ofNat s n) ((range (ofNat s n)).filter (· ∈ s)) := by
      simp only [Finset.ext_iff, mem_insert, mem_range, mem_filter]
      exact fun m =>
        ⟨fun h => by
          simp only [h.2, and_true_iff]
          exact Or.symm (lt_or_eq_of_le ((@lt_succ_iff_le _ _ _ ⟨m, h.2⟩ _).1 h.1)),
         fun h =>
          h.elim (fun h => h.symm ▸ ⟨lt_succ_self _, (ofNat s n).prop⟩) fun h =>
            ⟨h.1.trans (lt_succ_self _), h.2⟩⟩
    simp only [toFunAux_eq, ofNat, range_succ] at ih ⊢
    

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝¹ : Infinite ↑s
inst✝ : DecidablePred fun x => x ∈ s
n : ℕ
h₁ : ↑(ofNat s n) ∉ filter (fun x => x ∈ s) (range ↑(ofNat s n))
h₂ :
  filter (fun x => x ∈ s) (range ↑(succ (ofNat s n))) =
    insert (↑(ofNat s n)) (filter (fun x => x ∈ s) (range ↑(ofNat s n)))
ih : card (filter (fun x => x ∈ s) (range ↑(ofNat s n))) = n
⊢ card (filter (fun x => x ∈ s) (range ↑(succ (ofNat s (Nat.add n 0))))) = n + 1

Next tactic:
conv =>
      rhs
      rw [← ih, ← card_insert_of_not_mem h₁, ← h₂]
private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n
  | 0 => by
    rw [toFunAux_eq, card_eq_zero, eq_empty_iff_forall_not_mem]
    rintro n hn
    rw [mem_filter, ofNat, mem_range] at hn
    exact bot_le.not_lt (show (⟨n, hn.2⟩ : s) < ⊥ from hn.1)
  | n + 1 => by
    have ih : toFunAux (ofNat s n) = n := right_inverse_aux n
    have h₁ : (ofNat s n : ℕ) ∉ (range (ofNat s n)).filter (· ∈ s) := by simp
    have h₂ : (range (succ (ofNat s n))).filter (· ∈ s) =
        insert ↑(ofNat s n) ((range (ofNat s n)).filter (· ∈ s)) := by
      simp only [Finset.ext_iff, mem_insert, mem_range, mem_filter]
      exact fun m =>
        ⟨fun h => by
          simp only [h.2, and_true_iff]
          exact Or.symm (lt_or_eq_of_le ((@lt_succ_iff_le _ _ _ ⟨m, h.2⟩ _).1 h.1)),
         fun h =>
          h.elim (fun h => h.symm ▸ ⟨lt_succ_self _, (ofNat s n).prop⟩) fun h =>
            ⟨h.1.trans (lt_succ_self _), h.2⟩⟩
    simp only [toFunAux_eq, ofNat, range_succ] at ih ⊢
    conv =>
      

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝¹ : Infinite ↑s
inst✝ : DecidablePred fun x => x ∈ s
n : ℕ
h₁ : ↑(ofNat s n) ∉ filter (fun x => x ∈ s) (range ↑(ofNat s n))
h₂ :
  filter (fun x => x ∈ s) (range ↑(succ (ofNat s n))) =
    insert (↑(ofNat s n)) (filter (fun x => x ∈ s) (range ↑(ofNat s n)))
ih : card (filter (fun x => x ∈ s) (range ↑(ofNat s n))) = n
| card (filter (fun x => x ∈ s) (range ↑(succ (ofNat s (Nat.add n 0))))) = n + 1

Next tactic:
rhs
      rw [← ih, ← card_insert_of_not_mem h₁, ← h₂]
private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n
  | 0 => by
    rw [toFunAux_eq, card_eq_zero, eq_empty_iff_forall_not_mem]
    rintro n hn
    rw [mem_filter, ofNat, mem_range] at hn
    exact bot_le.not_lt (show (⟨n, hn.2⟩ : s) < ⊥ from hn.1)
  | n + 1 => by
    have ih : toFunAux (ofNat s n) = n := right_inverse_aux n
    have h₁ : (ofNat s n : ℕ) ∉ (range (ofNat s n)).filter (· ∈ s) := by simp
    have h₂ : (range (succ (ofNat s n))).filter (· ∈ s) =
        insert ↑(ofNat s n) ((range (ofNat s n)).filter (· ∈ s)) := by
      simp only [Finset.ext_iff, mem_insert, mem_range, mem_filter]
      exact fun m =>
        ⟨fun h => by
          simp only [h.2, and_true_iff]
          exact Or.symm (lt_or_eq_of_le ((@lt_succ_iff_le _ _ _ ⟨m, h.2⟩ _).1 h.1)),
         fun h =>
          h.elim (fun h => h.symm ▸ ⟨lt_succ_self _, (ofNat s n).prop⟩) fun h =>
            ⟨h.1.trans (lt_succ_self _), h.2⟩⟩
    simp only [toFunAux_eq, ofNat, range_succ] at ih ⊢
    conv =>
      

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝¹ : Infinite ↑s
inst✝ : DecidablePred fun x => x ∈ s
n : ℕ
h₁ : ↑(ofNat s n) ∉ filter (fun x => x ∈ s) (range ↑(ofNat s n))
h₂ :
  filter (fun x => x ∈ s) (range ↑(succ (ofNat s n))) =
    insert (↑(ofNat s n)) (filter (fun x => x ∈ s) (range ↑(ofNat s n)))
ih : card (filter (fun x => x ∈ s) (range ↑(ofNat s n))) = n
| card (filter (fun x => x ∈ s) (range ↑(succ (ofNat s (Nat.add n 0))))) = n + 1

Next tactic:
rhs
private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n
  | 0 => by
    rw [toFunAux_eq, card_eq_zero, eq_empty_iff_forall_not_mem]
    rintro n hn
    rw [mem_filter, ofNat, mem_range] at hn
    exact bot_le.not_lt (show (⟨n, hn.2⟩ : s) < ⊥ from hn.1)
  | n + 1 => by
    have ih : toFunAux (ofNat s n) = n := right_inverse_aux n
    have h₁ : (ofNat s n : ℕ) ∉ (range (ofNat s n)).filter (· ∈ s) := by simp
    have h₂ : (range (succ (ofNat s n))).filter (· ∈ s) =
        insert ↑(ofNat s n) ((range (ofNat s n)).filter (· ∈ s)) := by
      simp only [Finset.ext_iff, mem_insert, mem_range, mem_filter]
      exact fun m =>
        ⟨fun h => by
          simp only [h.2, and_true_iff]
          exact Or.symm (lt_or_eq_of_le ((@lt_succ_iff_le _ _ _ ⟨m, h.2⟩ _).1 h.1)),
         fun h =>
          h.elim (fun h => h.symm ▸ ⟨lt_succ_self _, (ofNat s n).prop⟩) fun h =>
            ⟨h.1.trans (lt_succ_self _), h.2⟩⟩
    simp only [toFunAux_eq, ofNat, range_succ] at ih ⊢
    conv =>
      rhs
      

Proof state:
α : Type u_1
β : Type u_2
s : Set ℕ
inst✝¹ : Infinite ↑s
inst✝ : DecidablePred fun x => x ∈ s
n : ℕ
h₁ : ↑(ofNat s n) ∉ filter (fun x => x ∈ s) (range ↑(ofNat s n))
h₂ :
  filter (fun x => x ∈ s) (range ↑(succ (ofNat s n))) =
    insert (↑(ofNat s n)) (filter (fun x => x ∈ s) (range ↑(ofNat s n)))
ih : card (filter (fun x => x ∈ s) (range ↑(ofNat s n))) = n
| n + 1

Next tactic:
rw [← ih, ← card_insert_of_not_mem h₁, ← h₂]
/-- An infinite encodable type is denumerable. -/
def ofEncodableOfInfinite (α : Type*) [Encodable α] [Infinite α] : Denumerable α := by
  

Proof state:
α✝ : Type u_1
β : Type u_2
α : Type u_3
inst✝¹ : Encodable α
inst✝ : Infinite α
⊢ Denumerable α

Next tactic:
letI := @decidableRangeEncode α _
/-- An infinite encodable type is denumerable. -/
def ofEncodableOfInfinite (α : Type*) [Encodable α] [Infinite α] : Denumerable α := by
  letI := @decidableRangeEncode α _
  

Proof state:
α✝ : Type u_1
β : Type u_2
α : Type u_3
inst✝¹ : Encodable α
inst✝ : Infinite α
this : DecidablePred fun x => x ∈ Set.range encode := decidableRangeEncode α
⊢ Denumerable α

Next tactic:
letI : Infinite (Set.range (@encode α _)) :=
    Infinite.of_injective _ (Equiv.ofInjective _ encode_injective).injective
/-- An infinite encodable type is denumerable. -/
def ofEncodableOfInfinite (α : Type*) [Encodable α] [Infinite α] : Denumerable α := by
  letI := @decidableRangeEncode α _
  letI : Infinite (Set.range (@encode α _)) :=
    Infinite.of_injective _ (Equiv.ofInjective _ encode_injective).injective
  

Proof state:
α✝ : Type u_1
β : Type u_2
α : Type u_3
inst✝¹ : Encodable α
inst✝ : Infinite α
this✝ : DecidablePred fun x => x ∈ Set.range encode := decidableRangeEncode α
this : Infinite ↑(Set.range encode) :=
  Infinite.of_injective (⇑(Equiv.ofInjective encode encode_injective))
    (Equiv.injective (Equiv.ofInjective encode encode_injective))
⊢ Denumerable α

Next tactic:
letI := Nat.Subtype.denumerable (Set.range (@encode α _))
/-- An infinite encodable type is denumerable. -/
def ofEncodableOfInfinite (α : Type*) [Encodable α] [Infinite α] : Denumerable α := by
  letI := @decidableRangeEncode α _
  letI : Infinite (Set.range (@encode α _)) :=
    Infinite.of_injective _ (Equiv.ofInjective _ encode_injective).injective
  letI := Nat.Subtype.denumerable (Set.range (@encode α _))
  

Proof state:
α✝ : Type u_1
β : Type u_2
α : Type u_3
inst✝¹ : Encodable α
inst✝ : Infinite α
this✝¹ : DecidablePred fun x => x ∈ Set.range encode := decidableRangeEncode α
this✝ : Infinite ↑(Set.range encode) :=
  Infinite.of_injective (⇑(Equiv.ofInjective encode encode_injective))
    (Equiv.injective (Equiv.ofInjective encode encode_injective))
this : Denumerable ↑(Set.range encode) := Subtype.denumerable (Set.range encode)
⊢ Denumerable α

Next tactic:
exact Denumerable.ofEquiv (Set.range (@encode α _)) (equivRangeEncode α)
instance nonempty_equiv_of_countable [Countable α] [Infinite α] [Countable β] [Infinite β] :
    Nonempty (α ≃ β) := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝³ : Countable α
inst✝² : Infinite α
inst✝¹ : Countable β
inst✝ : Infinite β
⊢ Nonempty (α ≃ β)

Next tactic:
cases nonempty_denumerable α
instance nonempty_equiv_of_countable [Countable α] [Infinite α] [Countable β] [Infinite β] :
    Nonempty (α ≃ β) := by
  cases nonempty_denumerable α
  

Proof state:
case intro
α : Type u_1
β : Type u_2
inst✝³ : Countable α
inst✝² : Infinite α
inst✝¹ : Countable β
inst✝ : Infinite β
val✝ : Denumerable α
⊢ Nonempty (α ≃ β)

Next tactic:
cases nonempty_denumerable β
instance nonempty_equiv_of_countable [Countable α] [Infinite α] [Countable β] [Infinite β] :
    Nonempty (α ≃ β) := by
  cases nonempty_denumerable α
  cases nonempty_denumerable β
  

Proof state:
case intro.intro
α : Type u_1
β : Type u_2
inst✝³ : Countable α
inst✝² : Infinite α
inst✝¹ : Countable β
inst✝ : Infinite β
val✝¹ : Denumerable α
val✝ : Denumerable β
⊢ Nonempty (α ≃ β)

Next tactic:
exact ⟨(Denumerable.eqv _).trans (Denumerable.eqv _).symm⟩
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
⊢ IsTerminal (F.obj (op I))

Next tactic:
refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
⊢ Unique (Y ⟶ F.obj (op I))

Next tactic:
choose t h using hF (by tauto) (by tauto)
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  choose t h using hF (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
⊢ FamilyOfElements F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)

Next tactic:
tauto
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  choose t h using hF (by tauto) (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
⊢ FamilyOfElements.Compatible
    (let_fun em := Classical.propDecidable;
    fun ⦃Y⦄ f a => (_ : False).elim)

Next tactic:
tauto
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  choose t h using hF (by tauto) (by tauto)
  

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
t : F.obj (op I)
h :
  (fun t =>
        FamilyOfElements.IsAmalgamation
          (let_fun em := Classical.propDecidable;
          fun ⦃Y⦄ f a => (_ : False).elim)
          t)
      t ∧
    ∀ (y : F.obj (op I)),
      (fun t =>
            FamilyOfElements.IsAmalgamation
              (let_fun em := Classical.propDecidable;
              fun ⦃Y⦄ f a => (_ : False).elim)
              t)
          y →
        y = t
⊢ Unique (Y ⟶ F.obj (op I))

Next tactic:
exact ⟨⟨fun _ ↦ t⟩, fun a ↦ by ext; exact h.2 _ (by tauto)⟩
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  choose t h using hF (by tauto) (by tauto)
  exact ⟨⟨fun _ ↦ t⟩, fun a ↦ by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
t : F.obj (op I)
h :
  (fun t =>
        FamilyOfElements.IsAmalgamation
          (let_fun em := Classical.propDecidable;
          fun ⦃Y⦄ f a => (_ : False).elim)
          t)
      t ∧
    ∀ (y : F.obj (op I)),
      (fun t =>
            FamilyOfElements.IsAmalgamation
              (let_fun em := Classical.propDecidable;
              fun ⦃Y⦄ f a => (_ : False).elim)
              t)
          y →
        y = t
a : Y ⟶ F.obj (op I)
⊢ a = default

Next tactic:
ext
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  choose t h using hF (by tauto) (by tauto)
  exact ⟨⟨fun _ ↦ t⟩, fun a ↦ by ext; 

Proof state:
case h
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
t : F.obj (op I)
h :
  (fun t =>
        FamilyOfElements.IsAmalgamation
          (let_fun em := Classical.propDecidable;
          fun ⦃Y⦄ f a => (_ : False).elim)
          t)
      t ∧
    ∀ (y : F.obj (op I)),
      (fun t =>
            FamilyOfElements.IsAmalgamation
              (let_fun em := Classical.propDecidable;
              fun ⦃Y⦄ f a => (_ : False).elim)
              t)
          y →
        y = t
a : Y ⟶ F.obj (op I)
a✝ : Y
⊢ a a✝ = default a✝

Next tactic:
exact h.2 _ (by tauto)
variable (I) in
/--
If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any
object, then `F` takes that object to the terminal object.
-/
noncomputable
def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by
  refine @IsTerminal.ofUnique _ _ _ fun Y ↦ ?_
  choose t h using hF (by tauto) (by tauto)
  exact ⟨⟨fun _ ↦ t⟩, fun a ↦ by ext; exact h.2 _ (by 

Proof state:
C : Type u
inst✝ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
Y : Type (max u v)
t : F.obj (op I)
h :
  (fun t =>
        FamilyOfElements.IsAmalgamation
          (let_fun em := Classical.propDecidable;
          fun ⦃Y⦄ f a => (_ : False).elim)
          t)
      t ∧
    ∀ (y : F.obj (op I)),
      (fun t =>
            FamilyOfElements.IsAmalgamation
              (let_fun em := Classical.propDecidable;
              fun ⦃Y⦄ f a => (_ : False).elim)
              t)
          y →
        y = t
a : Y ⟶ F.obj (op I)
a✝ : Y
⊢ (fun t =>
      FamilyOfElements.IsAmalgamation
        (let_fun em := Classical.propDecidable;
        fun ⦃Y⦄ f a => (_ : False).elim)
        t)
    (a a✝)

Next tactic:
tauto
/--
The two parallel maps in the equalizer diagram for the sheaf condition corresponding to the
inclusion maps in a disjoint coproduct are equal.
-/
theorem firstMap_eq_secondMap : Equalizer.Presieve.Arrows.firstMap F X c.inj =
    Equalizer.Presieve.Arrows.secondMap F X c.inj := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
hI : IsInitial I
α : Type
X : α → C
c : Cofan X
hc : IsColimit c
inst✝² : hasPullbacks (ofArrows X (Cofan.inj c))
inst✝¹ : HasInitial C
inst✝ : ∀ (i : α), Mono (Cofan.inj c i)
hd : ∀ (i j : α), i ≠ j → IsPullback (initial.to (X i)) (initial.to (X j)) (Cofan.inj c i) (Cofan.inj c j)
⊢ Equalizer.Presieve.Arrows.firstMap F X (Cofan.inj c) = Equalizer.Presieve.Arrows.secondMap F X (Cofan.inj c)

Next tactic:
ext a ⟨i, j⟩
/--
The two parallel maps in the equalizer diagram for the sheaf condition corresponding to the
inclusion maps in a disjoint coproduct are equal.
-/
theorem firstMap_eq_secondMap : Equalizer.Presieve.Arrows.firstMap F X c.inj =
    Equalizer.Presieve.Arrows.secondMap F X c.inj := by
  ext a ⟨i, j⟩
  

Proof state:
case h.h.mk
C : Type u
inst✝³ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
hI : IsInitial I
α : Type
X : α → C
c : Cofan X
hc : IsColimit c
inst✝² : hasPullbacks (ofArrows X (Cofan.inj c))
inst✝¹ : HasInitial C
inst✝ : ∀ (i : α), Mono (Cofan.inj c i)
hd : ∀ (i j : α), i ≠ j → IsPullback (initial.to (X i)) (initial.to (X j)) (Cofan.inj c i) (Cofan.inj c j)
a : Equalizer.Presieve.Arrows.FirstObj F X
i j : α
⊢ Pi.π (fun ij => F.obj (op (pullback (Cofan.inj c ij.1) (Cofan.inj c ij.2)))) (i, j)
      (Equalizer.Presieve.Arrows.firstMap F X (Cofan.inj c) a) =
    Pi.π (fun ij => F.obj (op (pullback (Cofan.inj c ij.1) (Cofan.inj c ij.2)))) (i, j)
      (Equalizer.Presieve.Arrows.secondMap F X (Cofan.inj c) a)

Next tactic:
simp only [Equalizer.Presieve.Arrows.firstMap, Types.pi_lift_π_apply, types_comp_apply,
    Equalizer.Presieve.Arrows.secondMap]
/--
The two parallel maps in the equalizer diagram for the sheaf condition corresponding to the
inclusion maps in a disjoint coproduct are equal.
-/
theorem firstMap_eq_secondMap : Equalizer.Presieve.Arrows.firstMap F X c.inj =
    Equalizer.Presieve.Arrows.secondMap F X c.inj := by
  ext a ⟨i, j⟩
  simp only [Equalizer.Presieve.Arrows.firstMap, Types.pi_lift_π_apply, types_comp_apply,
    Equalizer.Presieve.Arrows.secondMap]
  

Proof state:
case h.h.mk
C : Type u
inst✝³ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
hI : IsInitial I
α : Type
X : α → C
c : Cofan X
hc : IsColimit c
inst✝² : hasPullbacks (ofArrows X (Cofan.inj c))
inst✝¹ : HasInitial C
inst✝ : ∀ (i : α), Mono (Cofan.inj c i)
hd : ∀ (i j : α), i ≠ j → IsPullback (initial.to (X i)) (initial.to (X j)) (Cofan.inj c i) (Cofan.inj c j)
a : Equalizer.Presieve.Arrows.FirstObj F X
i j : α
⊢ F.map pullback.fst.op (Pi.π (fun i => F.obj (op (X i))) i a) =
    F.map pullback.snd.op (Pi.π (fun i => F.obj (op (X i))) j a)

Next tactic:
by_cases hi : i = j
/--
The two parallel maps in the equalizer diagram for the sheaf condition corresponding to the
inclusion maps in a disjoint coproduct are equal.
-/
theorem firstMap_eq_secondMap : Equalizer.Presieve.Arrows.firstMap F X c.inj =
    Equalizer.Presieve.Arrows.secondMap F X c.inj := by
  ext a ⟨i, j⟩
  simp only [Equalizer.Presieve.Arrows.firstMap, Types.pi_lift_π_apply, types_comp_apply,
    Equalizer.Presieve.Arrows.secondMap]
  by_cases hi : i = j
  · 

Proof state:
case pos
C : Type u
inst✝³ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
hI : IsInitial I
α : Type
X : α → C
c : Cofan X
hc : IsColimit c
inst✝² : hasPullbacks (ofArrows X (Cofan.inj c))
inst✝¹ : HasInitial C
inst✝ : ∀ (i : α), Mono (Cofan.inj c i)
hd : ∀ (i j : α), i ≠ j → IsPullback (initial.to (X i)) (initial.to (X j)) (Cofan.inj c i) (Cofan.inj c j)
a : Equalizer.Presieve.Arrows.FirstObj F X
i j : α
hi : i = j
⊢ F.map pullback.fst.op (Pi.π (fun i => F.obj (op (X i))) i a) =
    F.map pullback.snd.op (Pi.π (fun i => F.obj (op (X i))) j a)

Next tactic:
rw [hi, Mono.right_cancellation _ _ pullback.condition]
/--
The two parallel maps in the equalizer diagram for the sheaf condition corresponding to the
inclusion maps in a disjoint coproduct are equal.
-/
theorem firstMap_eq_secondMap : Equalizer.Presieve.Arrows.firstMap F X c.inj =
    Equalizer.Presieve.Arrows.secondMap F X c.inj := by
  ext a ⟨i, j⟩
  simp only [Equalizer.Presieve.Arrows.firstMap, Types.pi_lift_π_apply, types_comp_apply,
    Equalizer.Presieve.Arrows.secondMap]
  by_cases hi : i = j
  · rw [hi, Mono.right_cancellation _ _ pullback.condition]
  · 

Proof state:
case neg
C : Type u
inst✝³ : Category.{v, u} C
I : C
F : Cᵒᵖ ⥤ Type (max u v)
hF : IsSheafFor F (ofArrows Empty.elim fun a => IsEmpty.elim instIsEmptyEmpty a)
hI : IsInitial I
α : Type
X : α → C
c : Cofan X
hc : IsColimit c
inst✝² : hasPullbacks (ofArrows X (Cofan.inj c))
inst✝¹ : HasInitial C
inst✝ : ∀ (i : α), Mono (Cofan.inj c i)
hd : ∀ (i j : α), i ≠ j → IsPullback (initial.to (X i)) (initial.to (X j)) (Cofan.inj c i) (Cofan.inj c j)
a : Equalizer.Presieve.Arrows.FirstObj F X
i j : α
hi : ¬i = j
⊢ F.map pullback.fst.op (Pi.π (fun i => F.obj (op (X i))) i a) =
    F.map pullback.snd.op (Pi.π (fun i => F.obj (op (X i))) j a)

Next tactic:
have := preservesTerminalOfIsSheafForEmpty F hF hI