l3lab/ntp-mathlib huggingface dataset:
theorem isSheaf_yoneda' {α : Type u} : IsSheaf typesGrothendieckTopology (yoneda.obj α) :=
  fun β S hs x hx =>
  ⟨fun y => x _ (hs y) PUnit.unit, fun γ f h =>
    funext fun z => by
      convert congr_fun (hx (𝟙 _) (fun _ => z) (hs <| f z) h rfl) PUnit.unit using 1,
    fun f hf => funext fun y => by 

Proof state:
α β : Type u
S : Sieve β
hs : S ∈ GrothendieckTopology.sieves typesGrothendieckTopology β
x : FamilyOfElements (yoneda.obj α) S.arrows
hx : FamilyOfElements.Compatible x
f : (yoneda.obj α).obj (Opposite.op β)
hf : (fun t => FamilyOfElements.IsAmalgamation x t) f
y : (Opposite.op β).unop
⊢ f y = x (fun x => y) (_ : S.arrows fun x => y) PUnit.unit

Next tactic:
convert congr_fun (hf _ (hs y)) PUnit.unit
/-- Given a sheaf `S` on the category of types, construct a map
`(α → S(*)) → S(α)` that is inverse to `eval`. -/
noncomputable def typesGlue (S : Type uᵒᵖ ⥤ Type u) (hs : IsSheaf typesGrothendieckTopology S)
    (α : Type u) (f : α → S.obj (op PUnit)) : S.obj (op α) :=
  (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).amalgamate
    (fun β g hg => S.map (↾fun _ => PUnit.unit).op <| f <| g <| Classical.choose hg)
    fun β γ δ g₁ g₂ f₁ f₂ hf₁ hf₂ h =>
    (hs.isSheafFor _ _ (generate_discretePresieve_mem δ)).isSeparatedFor.ext fun ε g ⟨x, _⟩ => by
      

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
f : α → S.obj (op PUnit.{u + 1})
β γ δ : Type u
g₁ : δ ⟶ β
g₂ : δ ⟶ γ
f₁ : β ⟶ α
f₂ : γ ⟶ α
hf₁ : discretePresieve α f₁
hf₂ : discretePresieve α f₂
h : g₁ ≫ f₁ = g₂ ≫ f₂
ε : Type u
g : ε ⟶ δ
x✝ : discretePresieve δ g
x : ε
h✝ : ∀ (y : ε), y = x
⊢ S.map g.op (S.map g₁.op ((fun β g hg => S.map (↾fun x => PUnit.unit).op (f (g (Classical.choose hg)))) β f₁ hf₁)) =
    S.map g.op (S.map g₂.op ((fun β g hg => S.map (↾fun x => PUnit.unit).op (f (g (Classical.choose hg)))) γ f₂ hf₂))

Next tactic:
have : f₁ (Classical.choose hf₁) = f₂ (Classical.choose hf₂) :=
        Classical.choose_spec hf₁ (g₁ <| g x) ▸
          Classical.choose_spec hf₂ (g₂ <| g x) ▸ congr_fun h _
/-- Given a sheaf `S` on the category of types, construct a map
`(α → S(*)) → S(α)` that is inverse to `eval`. -/
noncomputable def typesGlue (S : Type uᵒᵖ ⥤ Type u) (hs : IsSheaf typesGrothendieckTopology S)
    (α : Type u) (f : α → S.obj (op PUnit)) : S.obj (op α) :=
  (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).amalgamate
    (fun β g hg => S.map (↾fun _ => PUnit.unit).op <| f <| g <| Classical.choose hg)
    fun β γ δ g₁ g₂ f₁ f₂ hf₁ hf₂ h =>
    (hs.isSheafFor _ _ (generate_discretePresieve_mem δ)).isSeparatedFor.ext fun ε g ⟨x, _⟩ => by
      have : f₁ (Classical.choose hf₁) = f₂ (Classical.choose hf₂) :=
        Classical.choose_spec hf₁ (g₁ <| g x) ▸
          Classical.choose_spec hf₂ (g₂ <| g x) ▸ congr_fun h _
      

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
f : α → S.obj (op PUnit.{u + 1})
β γ δ : Type u
g₁ : δ ⟶ β
g₂ : δ ⟶ γ
f₁ : β ⟶ α
f₂ : γ ⟶ α
hf₁ : discretePresieve α f₁
hf₂ : discretePresieve α f₂
h : g₁ ≫ f₁ = g₂ ≫ f₂
ε : Type u
g : ε ⟶ δ
x✝ : discretePresieve δ g
x : ε
h✝ : ∀ (y : ε), y = x
this : f₁ (Classical.choose hf₁) = f₂ (Classical.choose hf₂)
⊢ S.map g.op (S.map g₁.op ((fun β g hg => S.map (↾fun x => PUnit.unit).op (f (g (Classical.choose hg)))) β f₁ hf₁)) =
    S.map g.op (S.map g₂.op ((fun β g hg => S.map (↾fun x => PUnit.unit).op (f (g (Classical.choose hg)))) γ f₂ hf₂))

Next tactic:
simp_rw [← FunctorToTypes.map_comp_apply, this, ← op_comp]
/-- Given a sheaf `S` on the category of types, construct a map
`(α → S(*)) → S(α)` that is inverse to `eval`. -/
noncomputable def typesGlue (S : Type uᵒᵖ ⥤ Type u) (hs : IsSheaf typesGrothendieckTopology S)
    (α : Type u) (f : α → S.obj (op PUnit)) : S.obj (op α) :=
  (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).amalgamate
    (fun β g hg => S.map (↾fun _ => PUnit.unit).op <| f <| g <| Classical.choose hg)
    fun β γ δ g₁ g₂ f₁ f₂ hf₁ hf₂ h =>
    (hs.isSheafFor _ _ (generate_discretePresieve_mem δ)).isSeparatedFor.ext fun ε g ⟨x, _⟩ => by
      have : f₁ (Classical.choose hf₁) = f₂ (Classical.choose hf₂) :=
        Classical.choose_spec hf₁ (g₁ <| g x) ▸
          Classical.choose_spec hf₂ (g₂ <| g x) ▸ congr_fun h _
      simp_rw [← FunctorToTypes.map_comp_apply, this, ← op_comp]
      

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
f : α → S.obj (op PUnit.{u + 1})
β γ δ : Type u
g₁ : δ ⟶ β
g₂ : δ ⟶ γ
f₁ : β ⟶ α
f₂ : γ ⟶ α
hf₁ : discretePresieve α f₁
hf₂ : discretePresieve α f₂
h : g₁ ≫ f₁ = g₂ ≫ f₂
ε : Type u
g : ε ⟶ δ
x✝ : discretePresieve δ g
x : ε
h✝ : ∀ (y : ε), y = x
this : f₁ (Classical.choose hf₁) = f₂ (Classical.choose hf₂)
⊢ S.map (g ≫ g₁ ≫ ↾fun x => PUnit.unit).op (f (f₂ (Classical.choose hf₂))) =
    S.map (g ≫ g₂ ≫ ↾fun x => PUnit.unit).op (f (f₂ (Classical.choose hf₂)))

Next tactic:
rfl
theorem eval_typesGlue {S hs α} (f) : eval.{u} S α (typesGlue S hs α f) = f := by
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
f : α → S.obj (op PUnit.{u + 1})
⊢ eval S α (typesGlue S hs α f) = f

Next tactic:
funext x
theorem eval_typesGlue {S hs α} (f) : eval.{u} S α (typesGlue S hs α f) = f := by
  funext x
  

Proof state:
case h
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
f : α → S.obj (op PUnit.{u + 1})
x : α
⊢ eval S α (typesGlue S hs α f) x = f x

Next tactic:
apply (IsSheafFor.valid_glue _ _ _ <| ⟨PUnit.unit, fun _ => Subsingleton.elim _ _⟩).trans
theorem eval_typesGlue {S hs α} (f) : eval.{u} S α (typesGlue S hs α f) = f := by
  funext x
  apply (IsSheafFor.valid_glue _ _ _ <| ⟨PUnit.unit, fun _ => Subsingleton.elim _ _⟩).trans
  

Proof state:
case h
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
f : α → S.obj (op PUnit.{u + 1})
x : α
⊢ S.map (↾fun x => PUnit.unit).op (f ((↾fun x_1 => x) (Classical.choose (_ : ∃ x, ∀ (y : PUnit.{u + 1}), y = x)))) = f x

Next tactic:
convert FunctorToTypes.map_id_apply S _
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
⊢ typesGlue S hs α (eval S α s) = s

Next tactic:
apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
⊢ ∀ ⦃Y : Type u⦄ ⦃f : Y ⟶ α⦄, discretePresieve α f → S.map f.op (typesGlue S hs α (eval S α s)) = S.map f.op s

Next tactic:
intro β f hf
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
⊢ S.map f.op (typesGlue S hs α (eval S α s)) = S.map f.op s

Next tactic:
apply (IsSheafFor.valid_glue _ _ _ hf).trans
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  apply (IsSheafFor.valid_glue _ _ _ hf).trans
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
⊢ S.map (↾fun x => PUnit.unit).op (eval S α s (f (Classical.choose hf))) = S.map f.op s

Next tactic:
apply (FunctorToTypes.map_comp_apply _ _ _ _).symm.trans
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  apply (IsSheafFor.valid_glue _ _ _ hf).trans
  apply (FunctorToTypes.map_comp_apply _ _ _ _).symm.trans
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
⊢ S.map ((↾fun x => f (Classical.choose hf)).op ≫ (↾fun x => PUnit.unit).op) s = S.map f.op s

Next tactic:
rw [← op_comp]
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  apply (IsSheafFor.valid_glue _ _ _ hf).trans
  apply (FunctorToTypes.map_comp_apply _ _ _ _).symm.trans
  rw [← op_comp]
  --congr 2 -- Porting note: This tactic didn't work. Find an alternative.
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
⊢ S.map ((↾fun x => PUnit.unit) ≫ ↾fun x => f (Classical.choose hf)).op s = S.map f.op s

Next tactic:
suffices ((↾fun _ ↦ PUnit.unit) ≫ ↾fun _ ↦ f (Classical.choose hf)) = f by rw [this]
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  apply (IsSheafFor.valid_glue _ _ _ hf).trans
  apply (FunctorToTypes.map_comp_apply _ _ _ _).symm.trans
  rw [← op_comp]
  --congr 2 -- Porting note: This tactic didn't work. Find an alternative.
  suffices ((↾fun _ ↦ PUnit.unit) ≫ ↾fun _ ↦ f (Classical.choose hf)) = f by 

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
this : ((↾fun x => PUnit.unit) ≫ ↾fun x => f (Classical.choose hf)) = f
⊢ S.map ((↾fun x => PUnit.unit) ≫ ↾fun x => f (Classical.choose hf)).op s = S.map f.op s

Next tactic:
rw [this]
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  apply (IsSheafFor.valid_glue _ _ _ hf).trans
  apply (FunctorToTypes.map_comp_apply _ _ _ _).symm.trans
  rw [← op_comp]
  --congr 2 -- Porting note: This tactic didn't work. Find an alternative.
  suffices ((↾fun _ ↦ PUnit.unit) ≫ ↾fun _ ↦ f (Classical.choose hf)) = f by rw [this]
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
⊢ ((↾fun x => PUnit.unit) ≫ ↾fun x => f (Classical.choose hf)) = f

Next tactic:
funext x
theorem typesGlue_eval {S hs α} (s) : typesGlue.{u} S hs α (eval S α s) = s := by
  apply (hs.isSheafFor _ _ (generate_discretePresieve_mem α)).isSeparatedFor.ext
  intro β f hf
  apply (IsSheafFor.valid_glue _ _ _ hf).trans
  apply (FunctorToTypes.map_comp_apply _ _ _ _).symm.trans
  rw [← op_comp]
  --congr 2 -- Porting note: This tactic didn't work. Find an alternative.
  suffices ((↾fun _ ↦ PUnit.unit) ≫ ↾fun _ ↦ f (Classical.choose hf)) = f by rw [this]
  funext x
  

Proof state:
case h
S : Type uᵒᵖ ⥤ Type u
hs : IsSheaf typesGrothendieckTopology S
α : Type u
s : S.obj (op α)
β : Type u
f : β ⟶ α
hf : discretePresieve α f
x : β
⊢ ((↾fun x => PUnit.unit) ≫ ↾fun x => f (Classical.choose hf)) x = f x

Next tactic:
exact congr_arg f (Classical.choose_spec hf x).symm
theorem eval_map (S : Type uᵒᵖ ⥤ Type u) (α β) (f : β ⟶ α) (s x) :
    eval S β (S.map f.op s) x = eval S α s (f x) := by
  

Proof state:
S : Type uᵒᵖ ⥤ Type u
α β : Type u
f : β ⟶ α
s : S.obj (op α)
x : β
⊢ eval S β (S.map f.op s) x = eval S α s (f x)

Next tactic:
simp_rw [eval, ← FunctorToTypes.map_comp_apply, ← op_comp]
theorem eval_map (S : Type uᵒᵖ ⥤ Type u) (α β) (f : β ⟶ α) (s x) :
    eval S β (S.map f.op s) x = eval S α s (f x) := by
  simp_rw [eval, ← FunctorToTypes.map_comp_apply, ← op_comp]; 

Proof state:
S : Type uᵒᵖ ⥤ Type u
α β : Type u
f : β ⟶ α
s : S.obj (op α)
x : β
⊢ S.map ((↾fun x_1 => x) ≫ f).op s = S.map (↾fun x_1 => f x).op s

Next tactic:
rfl
/-- Given a sheaf `S`, construct an isomorphism `S ≅ [-, S(*)]`. -/
@[simps]
noncomputable def equivYoneda' (S : SheafOfTypes typesGrothendieckTopology) :
    S ≅ yoneda'.obj (S.1.obj (op PUnit)) where
  hom := ⟨(equivYoneda S.1 S.2).hom⟩
  inv := ⟨(equivYoneda S.1 S.2).inv⟩
  hom_inv_id := by 

Proof state:
S : SheafOfTypes typesGrothendieckTopology
⊢ { val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).hom } ≫
      { val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).inv } =
    𝟙 S

Next tactic:
ext1
/-- Given a sheaf `S`, construct an isomorphism `S ≅ [-, S(*)]`. -/
@[simps]
noncomputable def equivYoneda' (S : SheafOfTypes typesGrothendieckTopology) :
    S ≅ yoneda'.obj (S.1.obj (op PUnit)) where
  hom := ⟨(equivYoneda S.1 S.2).hom⟩
  inv := ⟨(equivYoneda S.1 S.2).inv⟩
  hom_inv_id := by ext1; 

Proof state:
case w
S : SheafOfTypes typesGrothendieckTopology
⊢ ({ val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).hom } ≫
        { val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).inv }).val =
    (𝟙 S).val

Next tactic:
apply (equivYoneda S.1 S.2).hom_inv_id
/-- Given a sheaf `S`, construct an isomorphism `S ≅ [-, S(*)]`. -/
@[simps]
noncomputable def equivYoneda' (S : SheafOfTypes typesGrothendieckTopology) :
    S ≅ yoneda'.obj (S.1.obj (op PUnit)) where
  hom := ⟨(equivYoneda S.1 S.2).hom⟩
  inv := ⟨(equivYoneda S.1 S.2).inv⟩
  hom_inv_id := by ext1; apply (equivYoneda S.1 S.2).hom_inv_id
  inv_hom_id := by 

Proof state:
S : SheafOfTypes typesGrothendieckTopology
⊢ { val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).inv } ≫
      { val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).hom } =
    𝟙 (yoneda'.obj (S.val.obj (op PUnit.{?u.22129 + 1})))

Next tactic:
ext1
/-- Given a sheaf `S`, construct an isomorphism `S ≅ [-, S(*)]`. -/
@[simps]
noncomputable def equivYoneda' (S : SheafOfTypes typesGrothendieckTopology) :
    S ≅ yoneda'.obj (S.1.obj (op PUnit)) where
  hom := ⟨(equivYoneda S.1 S.2).hom⟩
  inv := ⟨(equivYoneda S.1 S.2).inv⟩
  hom_inv_id := by ext1; apply (equivYoneda S.1 S.2).hom_inv_id
  inv_hom_id := by ext1; 

Proof state:
case w
S : SheafOfTypes typesGrothendieckTopology
⊢ ({ val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).inv } ≫
        { val := (equivYoneda S.val (_ : IsSheaf typesGrothendieckTopology S.val)).hom }).val =
    (𝟙 (yoneda'.obj (S.val.obj (op PUnit.{?u.22129 + 1})))).val

Next tactic:
apply (equivYoneda S.1 S.2).inv_hom_id
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  

Proof state:
⊢ typesGrothendieckTopology = Sheaf.canonicalTopology (Type u)

Next tactic:
refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  

Proof state:
⊢ typesGrothendieckTopology ∈ Sheaf.finestTopologySingle '' Set.range yoneda.toPrefunctor.obj

Next tactic:
refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
  

Proof state:
⊢ (Sheaf.finestTopologySingle (yoneda.obj (ULift.{u, 0} Bool))).sieves = typesGrothendieckTopology.sieves

Next tactic:
funext α
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
  funext α
  

Proof state:
case h
α : Type u
⊢ GrothendieckTopology.sieves (Sheaf.finestTopologySingle (yoneda.obj (ULift.{u, 0} Bool))) α =
    GrothendieckTopology.sieves typesGrothendieckTopology α

Next tactic:
ext S
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
  funext α
  ext S
  

Proof state:
case h.h
α : Type u
S : Sieve α
⊢ S ∈ GrothendieckTopology.sieves (Sheaf.finestTopologySingle (yoneda.obj (ULift.{u, 0} Bool))) α ↔
    S ∈ GrothendieckTopology.sieves typesGrothendieckTopology α

Next tactic:
refine' ⟨fun hs x => _, fun hs β f => isSheaf_yoneda' _ fun y => hs _⟩
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
  funext α
  ext S
  refine' ⟨fun hs x => _, fun hs β f => isSheaf_yoneda' _ fun y => hs _⟩
  

Proof state:
case h.h
α : Type u
S : Sieve α
hs : S ∈ GrothendieckTopology.sieves (Sheaf.finestTopologySingle (yoneda.obj (ULift.{u, 0} Bool))) α
x : α
⊢ S.arrows fun x_1 => x

Next tactic:
by_contra hsx
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
  funext α
  ext S
  refine' ⟨fun hs x => _, fun hs β f => isSheaf_yoneda' _ fun y => hs _⟩
  by_contra hsx
  

Proof state:
case h.h
α : Type u
S : Sieve α
hs : S ∈ GrothendieckTopology.sieves (Sheaf.finestTopologySingle (yoneda.obj (ULift.{u, 0} Bool))) α
x : α
hsx : ¬S.arrows fun x_1 => x
⊢ False

Next tactic:
have : (fun _ => ULift.up true) = fun _ => ULift.up false :=
    (hs PUnit fun _ => x).isSeparatedFor.ext
      fun β f hf => funext fun y => hsx.elim <| S.2 hf fun _ => y
theorem typesGrothendieckTopology_eq_canonical :
    typesGrothendieckTopology.{u} = Sheaf.canonicalTopology (Type u) := by
  refine' le_antisymm subcanonical_typesGrothendieckTopology (sInf_le _)
  refine' ⟨yoneda.obj (ULift Bool), ⟨_, rfl⟩, GrothendieckTopology.ext _⟩
  funext α
  ext S
  refine' ⟨fun hs x => _, fun hs β f => isSheaf_yoneda' _ fun y => hs _⟩
  by_contra hsx
  have : (fun _ => ULift.up true) = fun _ => ULift.up false :=
    (hs PUnit fun _ => x).isSeparatedFor.ext
      fun β f hf => funext fun y => hsx.elim <| S.2 hf fun _ => y
  

Proof state:
case h.h
α : Type u
S : Sieve α
hs : S ∈ GrothendieckTopology.sieves (Sheaf.finestTopologySingle (yoneda.obj (ULift.{u, 0} Bool))) α
x : α
hsx : ¬S.arrows fun x_1 => x
this : (fun x => { down := true }) = fun x => { down := false }
⊢ False

Next tactic:
simp [Function.funext_iff] at this
@[simp]
theorem Finsupp.toDFinsupp_single (i : ι) (m : M) :
    (Finsupp.single i m).toDFinsupp = DFinsupp.single i m := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝¹ : DecidableEq ι
inst✝ : Zero M
i : ι
m : M
⊢ (toDFinsupp fun₀ | i => m) = DFinsupp.single i m

Next tactic:
ext
@[simp]
theorem Finsupp.toDFinsupp_single (i : ι) (m : M) :
    (Finsupp.single i m).toDFinsupp = DFinsupp.single i m := by
  ext
  

Proof state:
case h
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝¹ : DecidableEq ι
inst✝ : Zero M
i : ι
m : M
i✝ : ι
⊢ (toDFinsupp fun₀ | i => m) i✝ = (DFinsupp.single i m) i✝

Next tactic:
simp [Finsupp.single_apply, DFinsupp.single_apply]
@[simp]
theorem toDFinsupp_support (f : ι →₀ M) : f.toDFinsupp.support = f.support := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
f : ι →₀ M
⊢ DFinsupp.support (Finsupp.toDFinsupp f) = f.support

Next tactic:
ext
@[simp]
theorem toDFinsupp_support (f : ι →₀ M) : f.toDFinsupp.support = f.support := by
  ext
  

Proof state:
case a
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
f : ι →₀ M
a✝ : ι
⊢ a✝ ∈ DFinsupp.support (Finsupp.toDFinsupp f) ↔ a✝ ∈ f.support

Next tactic:
simp
/-- Interpret a homogenous `DFinsupp` as a `Finsupp`.

Note that the elaborator has a lot of trouble with this definition - it is often necessary to
write `(DFinsupp.toFinsupp f : ι →₀ M)` instead of `f.toFinsupp`, as for some unknown reason
using dot notation or omitting the type ascription prevents the type being resolved correctly. -/
def DFinsupp.toFinsupp (f : Π₀ _ : ι, M) : ι →₀ M :=
  ⟨f.support, f, fun i => by 

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
f : Π₀ (x : ι), M
i : ι
⊢ i ∈ support f ↔ f i ≠ 0

Next tactic:
simp only [DFinsupp.mem_support_iff]
@[simp]
theorem DFinsupp.toFinsupp_support (f : Π₀ _ : ι, M) : f.toFinsupp.support = f.support := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
f : Π₀ (x : ι), M
⊢ (toFinsupp f).support = support f

Next tactic:
ext
@[simp]
theorem DFinsupp.toFinsupp_support (f : Π₀ _ : ι, M) : f.toFinsupp.support = f.support := by
  ext
  

Proof state:
case a
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
f : Π₀ (x : ι), M
a✝ : ι
⊢ a✝ ∈ (toFinsupp f).support ↔ a✝ ∈ support f

Next tactic:
simp
@[simp]
theorem DFinsupp.toFinsupp_single (i : ι) (m : M) :
    (DFinsupp.single i m : Π₀ _ : ι, M).toFinsupp = Finsupp.single i m := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
i : ι
m : M
⊢ toFinsupp (single i m) = fun₀ | i => m

Next tactic:
ext
@[simp]
theorem DFinsupp.toFinsupp_single (i : ι) (m : M) :
    (DFinsupp.single i m : Π₀ _ : ι, M).toFinsupp = Finsupp.single i m := by
  ext
  

Proof state:
case h
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝² : DecidableEq ι
inst✝¹ : Zero M
inst✝ : (m : M) → Decidable (m ≠ 0)
i : ι
m : M
a✝ : ι
⊢ (toFinsupp (single i m)) a✝ = (fun₀ | i => m) a✝

Next tactic:
simp [Finsupp.single_apply, DFinsupp.single_apply]
@[simp]
theorem finsuppLequivDFinsupp_apply_apply [DecidableEq ι] [Semiring R] [AddCommMonoid M]
    [∀ m : M, Decidable (m ≠ 0)] [Module R M] :
      (↑(finsuppLequivDFinsupp (M := M) R) : (ι →₀ M) → _) = Finsupp.toDFinsupp := by
       

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁴ : DecidableEq ι
inst✝³ : Semiring R
inst✝² : AddCommMonoid M
inst✝¹ : (m : M) → Decidable (m ≠ 0)
inst✝ : Module R M
⊢ ⇑(finsuppLequivDFinsupp R) = Finsupp.toDFinsupp

Next tactic:
simp only [@LinearEquiv.coe_coe]
@[simp]
theorem finsuppLequivDFinsupp_apply_apply [DecidableEq ι] [Semiring R] [AddCommMonoid M]
    [∀ m : M, Decidable (m ≠ 0)] [Module R M] :
      (↑(finsuppLequivDFinsupp (M := M) R) : (ι →₀ M) → _) = Finsupp.toDFinsupp := by
       simp only [@LinearEquiv.coe_coe]; 

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁴ : DecidableEq ι
inst✝³ : Semiring R
inst✝² : AddCommMonoid M
inst✝¹ : (m : M) → Decidable (m ≠ 0)
inst✝ : Module R M
⊢ ⇑(finsuppLequivDFinsupp R) = Finsupp.toDFinsupp

Next tactic:
rfl
/-- `Finsupp.split` is an equivalence between `(Σ i, η i) →₀ N` and `Π₀ i, (η i →₀ N)`. -/
def sigmaFinsuppEquivDFinsupp [Zero N] : ((Σi, η i) →₀ N) ≃ Π₀ i, η i →₀ N where
  toFun f := ⟨split f, Trunc.mk ⟨(splitSupport f : Finset ι).val, fun i => by
          

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
η : ι → Type u_4
N : Type u_5
inst✝¹ : Semiring R
inst✝ : Zero N
f : (i : ι) × η i →₀ N
i : ι
⊢ i ∈ (splitSupport f).val ∨ split f i = 0

Next tactic:
rw [← Finset.mem_def, mem_splitSupport_iff_nonzero]
/-- `Finsupp.split` is an equivalence between `(Σ i, η i) →₀ N` and `Π₀ i, (η i →₀ N)`. -/
def sigmaFinsuppEquivDFinsupp [Zero N] : ((Σi, η i) →₀ N) ≃ Π₀ i, η i →₀ N where
  toFun f := ⟨split f, Trunc.mk ⟨(splitSupport f : Finset ι).val, fun i => by
          rw [← Finset.mem_def, mem_splitSupport_iff_nonzero]
          

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
η : ι → Type u_4
N : Type u_5
inst✝¹ : Semiring R
inst✝ : Zero N
f : (i : ι) × η i →₀ N
i : ι
⊢ split f i ≠ 0 ∨ split f i = 0

Next tactic:
exact (em _).symm