Skip to content

Commit 6f37168

Browse files
committed
feat: Add CategoryTheory.Sites.Coverage (#4113)
This PR adds the notion of a coverage, and constructs the natural Galois insertion between coverages and Grothendieck topologies. We also show that a `Type _`-valued presheaf is a sheaf for a coverage if and only if it is a sheaf for the associated Grothendieck topology. Co-authored-by: Adam Topaz <adamtopaz@users.noreply.github.com>
1 parent 8d40252 commit 6f37168

File tree

2 files changed

+370
-0
lines changed

2 files changed

+370
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ import Mathlib.CategoryTheory.SingleObj
743743
import Mathlib.CategoryTheory.Sites.Adjunction
744744
import Mathlib.CategoryTheory.Sites.CoverLifting
745745
import Mathlib.CategoryTheory.Sites.CoverPreserving
746+
import Mathlib.CategoryTheory.Sites.Coverage
746747
import Mathlib.CategoryTheory.Sites.DenseSubsite
747748
import Mathlib.CategoryTheory.Sites.Grothendieck
748749
import Mathlib.CategoryTheory.Sites.InducedTopology
Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
/-
2+
Copyright (c) 2023 Adam Topaz. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Adam Topaz
5+
-/
6+
7+
import Mathlib.CategoryTheory.Sites.SheafOfTypes
8+
9+
/-!
10+
11+
# Coverages
12+
13+
A coverage `K` on a category `C` is a set of presieves associated to every object `X : C`,
14+
called "covering presieves".
15+
This collection must satisfy a certain "pullback compatibility" condition, saying that
16+
whenever `S` is a covering presieve on `X` and `f : Y ⟶ X` is a morphism, then there exists
17+
some covering sieve `T` on `Y` such that `T` factors through `S` along `f`.
18+
19+
The main difference between a coverage and a Grothendieck pretopology is that we *do not*
20+
require `C` to have pullbacks.
21+
This is useful, for example, when we want to consider the Grothendieck topology on the category
22+
of extremally disconnected sets in the context of condensed mathematics.
23+
24+
A more concrete example: If `ℬ` is a basis for a topology on a type `X` (in the sense of
25+
`TopologicalSpace.IsTopologicalBasis`) then it naturally induces a coverage on `Opens X`
26+
whose associated Grothendieck topology is the one induced by the topology
27+
on `X` generated by `ℬ`. (Project: Formalize this!)
28+
29+
## Main Definitions and Results:
30+
31+
All definitions are in the `CategoryTheory` namespace.
32+
33+
- `Coverage C`: The type of coverages on `C`.
34+
- `Coverage.ofGrothendieck C`: A function which associates a coverage to any Grothendieck topology.
35+
- `Coverage.toGrothendieck C`: A function which associates a Grothendieck topology to any coverage.
36+
- `Coverage.gi`: The two functions above form a Galois insertion.
37+
- `Presieve.isSheaf_coverage`: Given `K : Coverage C` with associated
38+
Grothendieck topology `J`, a `Type _`-valued presheaf on `C` is a sheaf for `K` if and only if
39+
it is a sheaf for `J`.
40+
41+
# References
42+
We don't follow any particular reference, but the arguments can probably be distilled from
43+
the following sources:
44+
- [Elephant]: *Sketches of an Elephant*, P. T. Johnstone: C2.1.
45+
- [nLab, *Coverage*](https://ncatlab.org/nlab/show/coverage)
46+
-/
47+
48+
namespace CategoryTheory
49+
50+
variable {C : Type _} [Category C]
51+
52+
namespace Presieve
53+
54+
/--
55+
Given a morphism `f : Y ⟶ X`, a presieve `S` on `Y` and presieve `T` on `X`,
56+
we say that *`S` factors through `T` along `f`*, written `S.FactorsThruAlong T f`,
57+
provided that for any morphism `g : Z ⟶ Y` in `S`, there exists some
58+
morphism `e : W ⟶ X` in `T` and some morphism `i : Z ⟶ W` such that the obvious
59+
square commutes: `i ≫ e = g ≫ f`.
60+
61+
This is used in the definition of a coverage.
62+
-/
63+
def FactorsThruAlong {X Y : C} (S : Presieve Y) (T : Presieve X) (f : Y ⟶ X) : Prop :=
64+
∀ ⦃Z : C⦄ ⦃g : Z ⟶ Y⦄, S g →
65+
∃ (W : C) (i : Z ⟶ W) (e : W ⟶ X), T e ∧ i ≫ e = g ≫ f
66+
67+
/--
68+
Given `S T : Presieve X`, we say that `S` factors through `T` if any morphism in `S`
69+
factors through some morphism in `T`.
70+
71+
The lemma `Presieve.isSheafFor_of_factorsThru` gives a *sufficient* condition for a
72+
presheaf to be a sheaf for a presieve `T`, in terms of `S.FactorsThru T`, provided
73+
that the presheaf is a sheaf for `S`.
74+
-/
75+
def FactorsThru {X : C} (S T : Presieve X) : Prop :=
76+
∀ ⦃Z : C⦄ ⦃g : Z ⟶ X⦄, S g →
77+
∃ (W : C) (i : Z ⟶ W) (e : W ⟶ X), T e ∧ i ≫ e = g
78+
79+
@[simp]
80+
lemma factorsThruAlong_id {X : C} (S T : Presieve X) :
81+
S.FactorsThruAlong T (𝟙 X) ↔ S.FactorsThru T := by
82+
simp [FactorsThruAlong, FactorsThru]
83+
84+
lemma factorsThru_of_le {X : C} (S T : Presieve X) (h : S ≤ T) :
85+
S.FactorsThru T :=
86+
fun Y g hg => ⟨Y, 𝟙 _, g, h _ hg, by simp⟩
87+
88+
lemma le_of_factorsThru_sieve {X : C} (S : Presieve X) (T : Sieve X) (h : S.FactorsThru T) :
89+
S ≤ T := by
90+
rintro Y f hf
91+
obtain ⟨W, i, e, h1, rfl⟩ := h hf
92+
exact T.downward_closed h1 _
93+
94+
lemma factorsThru_top {X : C} (S : Presieve X) : S.FactorsThru ⊤ :=
95+
factorsThru_of_le _ _ le_top
96+
97+
lemma isSheafFor_of_factorsThru
98+
{X : C} {S T : Presieve X}
99+
(P : Cᵒᵖ ⥤ Type w)
100+
(H : S.FactorsThru T) (hS : S.IsSheafFor P)
101+
(h : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, T f → ∃ (R : Presieve Y),
102+
R.IsSeparatedFor P ∧ R.FactorsThruAlong S f):
103+
T.IsSheafFor P := by
104+
simp only [←Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
105+
choose W i e h1 h2 using H
106+
refine ⟨?_, fun x hx => ?_⟩
107+
· intro x y₁ y₂ h₁ h₂
108+
refine hS.1.ext (fun Y g hg => ?_)
109+
simp only [← h2 hg, op_comp, P.map_comp, types_comp_apply, h₁ _ (h1 _ ), h₂ _ (h1 _)]
110+
let y : S.FamilyOfElements P := fun Y g hg => P.map (i _).op (x (e hg) (h1 _))
111+
have hy : y.Compatible := by
112+
intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ h
113+
rw [← types_comp_apply (P.map (i h₁).op) (P.map g₁.op),
114+
← types_comp_apply (P.map (i h₂).op) (P.map g₂.op),
115+
← P.map_comp, ← op_comp, ← P.map_comp, ← op_comp]
116+
apply hx
117+
simp only [h2, h, Category.assoc]
118+
let ⟨_, h2'⟩ := hS
119+
obtain ⟨z, hz⟩ := h2' y hy
120+
refine ⟨z, fun Y g hg => ?_⟩
121+
obtain ⟨R, hR1, hR2⟩ := h hg
122+
choose WW ii ee hh1 hh2 using hR2
123+
refine hR1.ext (fun Q t ht => ?_)
124+
rw [← types_comp_apply (P.map g.op) (P.map t.op), ← P.map_comp, ← op_comp, ← hh2 ht,
125+
op_comp, P.map_comp, types_comp_apply, hz _ (hh1 _),
126+
← types_comp_apply _ (P.map (ii ht).op), ← P.map_comp, ← op_comp]
127+
apply hx
128+
simp only [Category.assoc, h2, hh2]
129+
130+
131+
end Presieve
132+
133+
variable (C) in
134+
/--
135+
The type `Coverage C` of coverages on `C`.
136+
A coverage is a collection of *covering* presieves on every object `X : C`,
137+
which satisfies a *pullback compatibility* condition.
138+
Explicitly, this condition says that whenever `S` is a covering presieve for `X` and
139+
`f : Y ⟶ X` is a morphism, then there exists some covering presieve `T` for `Y`
140+
such that `T` factors through `S` along `f`.
141+
-/
142+
@[ext]
143+
structure Coverage where
144+
/-- The collection of covering presieves for an object `X`. -/
145+
covering : ∀ (X : C), Set (Presieve X)
146+
/-- Given any covering sieve `S` on `X` and a morphism `f : Y ⟶ X`, there exists
147+
some covering sieve `T` on `Y` such that `T` factors through `S` along `f`. -/
148+
pullback : ∀ ⦃X Y : C⦄ (f : Y ⟶ X) (S : Presieve X) (_ : S ∈ covering X),
149+
∃ (T : Presieve Y), T ∈ covering Y ∧ T.FactorsThruAlong S f
150+
151+
namespace Coverage
152+
153+
instance : CoeFun (Coverage C) (fun _ => (X : C) → Set (Presieve X)) where
154+
coe := covering
155+
156+
variable (C) in
157+
/--
158+
Associate a coverage to any Grothendieck topology.
159+
If `J` is a Grothendieck topology, and `K` is the associated coverage, then a presieve
160+
`S` is a covering presieve for `K` if and only if the sieve that it generates is a
161+
covering sieve for `J`.
162+
-/
163+
def ofGrothendieck (J : GrothendieckTopology C) : Coverage C where
164+
covering X := { S | Sieve.generate S ∈ J X }
165+
pullback := by
166+
intro X Y f S (hS : Sieve.generate S ∈ J X)
167+
refine ⟨(Sieve.generate S).pullback f, ?_, fun Z g h => h⟩
168+
dsimp
169+
rw [Sieve.generate_sieve]
170+
exact J.pullback_stable _ hS
171+
172+
lemma ofGrothendieck_iff {X : C} {S : Presieve X} (J : GrothendieckTopology C) :
173+
S ∈ ofGrothendieck _ J X ↔ Sieve.generate S ∈ J X := Iff.rfl
174+
175+
/--
176+
An auxiliary definition used to define the Grothendieck topology associated to a
177+
coverage. See `Coverage.toGrothendieck`.
178+
-/
179+
inductive saturate (K : Coverage C) : (X : C) → Sieve X → Prop where
180+
| of (X : C) (S : Presieve X) (hS : S ∈ K X) : saturate K X (Sieve.generate S)
181+
| top (X : C) : saturate K X ⊤
182+
| transitive (X : C) (R S : Sieve X) :
183+
saturate K X R →
184+
(∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, R f → saturate K Y (S.pullback f)) →
185+
saturate K X S
186+
187+
lemma eq_top_pullback {X Y : C} {S T : Sieve X} (h : S ≤ T) (f : Y ⟶ X) (hf : S f) :
188+
T.pullback f = ⊤ := by
189+
ext Z ; intro g
190+
simp only [Sieve.pullback_apply, Sieve.top_apply, iff_true]
191+
apply h
192+
apply S.downward_closed
193+
exact hf
194+
195+
lemma saturate_of_superset (K : Coverage C) {X : C} {S T : Sieve X} (h : S ≤ T)
196+
(hS : saturate K X S) : saturate K X T := by
197+
apply saturate.transitive _ _ _ hS
198+
intro Y g hg
199+
rw [eq_top_pullback (h := h)]
200+
· apply saturate.top
201+
· assumption
202+
203+
variable (C) in
204+
/--
205+
The Grothendieck topology associated to a coverage `K`.
206+
It is defined *inductively* as follows:
207+
1. If `S` is a covering presieve for `K`, then the sieve generated by `S` is a covering
208+
sieve for the associated Grothendieck topology.
209+
2. The top sieves are in the associated Grothendieck topology.
210+
3. Add all sieves required by the *local character* axiom of a Grothendieck topology.
211+
212+
The pullback compatibility condition for a coverage ensures that the
213+
associated Grothendieck topology is pullback stable, and so an additional constructor
214+
in the inductive construction is not needed.
215+
-/
216+
def toGrothendieck (K : Coverage C) : GrothendieckTopology C where
217+
sieves := saturate K
218+
top_mem' := .top
219+
pullback_stable' := by
220+
intro X Y S f hS
221+
induction hS generalizing Y with
222+
| of X S hS =>
223+
obtain ⟨R,hR1,hR2⟩ := K.pullback f S hS
224+
suffices Sieve.generate R ≤ (Sieve.generate S).pullback f from
225+
saturate_of_superset _ this (saturate.of _ _ hR1)
226+
rintro Z g ⟨W, i, e, h1, h2⟩
227+
obtain ⟨WW, ii, ee, hh1, hh2⟩ := hR2 h1
228+
refine ⟨WW, i ≫ ii, ee, hh1, ?_⟩
229+
simp only [hh2, reassoc_of% h2, Category.assoc]
230+
| top X => apply saturate.top
231+
| transitive X R S _ hS H1 _ =>
232+
apply saturate.transitive
233+
apply H1 f
234+
intro Z g hg
235+
rw [← Sieve.pullback_comp]
236+
exact hS hg
237+
transitive' X S hS R hR := .transitive _ _ _ hS hR
238+
239+
instance : PartialOrder (Coverage C) where
240+
le A B := A.covering ≤ B.covering
241+
le_refl A X := le_refl _
242+
le_trans A B C h1 h2 X := le_trans (h1 X) (h2 X)
243+
le_antisymm A B h1 h2 := Coverage.ext A B <| funext <|
244+
fun X => le_antisymm (h1 X) (h2 X)
245+
246+
variable (C) in
247+
/--
248+
The two constructions `Coverage.toGrothendieck` and `Coverage.ofGrothendieck` form
249+
a Galois insertion.
250+
-/
251+
def gi : GaloisInsertion (toGrothendieck C) (ofGrothendieck C) where
252+
choice K _ := toGrothendieck _ K
253+
choice_eq := fun _ _ => rfl
254+
le_l_u J X S hS := by
255+
rw [← Sieve.generate_sieve S]
256+
apply saturate.of
257+
dsimp [ofGrothendieck]
258+
rwa [Sieve.generate_sieve S]
259+
gc K J := by
260+
constructor
261+
· intro H X S hS
262+
exact H _ <| saturate.of _ _ hS
263+
· intro H X S hS
264+
induction hS with
265+
| of X S hS => exact H _ hS
266+
| top => apply J.top_mem
267+
| transitive X R S _ _ H1 H2 => exact J.transitive H1 _ H2
268+
269+
/--
270+
An alternative characterization of the Grothendieck topology associated to a coverage `K`:
271+
it is the infimum of all Grothendieck topologies whose associated coverage contains `K`.
272+
-/
273+
theorem toGrothendieck_eq_sInf (K : Coverage C) : toGrothendieck _ K =
274+
sInf {J | K ≤ ofGrothendieck _ J } := by
275+
apply le_antisymm
276+
· apply le_sInf ; intro J hJ
277+
intro X S hS
278+
induction hS with
279+
| of X S hS => apply hJ ; assumption
280+
| top => apply J.top_mem
281+
| transitive X R S _ _ H1 H2 => exact J.transitive H1 _ H2
282+
· apply sInf_le
283+
intro X S hS
284+
apply saturate.of _ _ hS
285+
286+
end Coverage
287+
288+
open Coverage
289+
290+
namespace Presieve
291+
292+
/--
293+
The main theorem of this file: Given a coverage `K` on `C`,
294+
a `Type _`-valued presheaf on `C` is a sheaf for `K` if and only if it is a sheaf for
295+
the assocaited Grothendieck topology.
296+
-/
297+
theorem isSheaf_coverage (K : Coverage C) (P : Cᵒᵖ ⥤ Type w) :
298+
Presieve.IsSheaf (toGrothendieck _ K) P ↔
299+
(∀ {X : C} (R : Presieve X), R ∈ K X → Presieve.IsSheafFor P R) := by
300+
constructor
301+
· intro H X R hR
302+
rw [Presieve.isSheafFor_iff_generate]
303+
apply H _ <| saturate.of _ _ hR
304+
· intro H X S hS
305+
-- This is the key point of the proof:
306+
-- We must generalize the induction in the correct way.
307+
suffices ∀ ⦃Y : C⦄ (f : Y ⟶ X), Presieve.IsSheafFor P (S.pullback f).arrows by
308+
simpa using this (f := 𝟙 _)
309+
induction hS with
310+
| of X S hS =>
311+
intro Y f
312+
obtain ⟨T, hT1, hT2⟩ := K.pullback f S hS
313+
apply Presieve.isSheafFor_of_factorsThru (S := T)
314+
· intro Z g hg
315+
obtain ⟨W, i, e, h1, h2⟩ := hT2 hg
316+
exact ⟨Z, 𝟙 _, g, ⟨W, i, e, h1, h2⟩, by simp⟩
317+
· apply H ; assumption
318+
· intro Z g _
319+
obtain ⟨R, hR1, hR2⟩ := K.pullback g _ hT1
320+
refine ⟨R, (H _ hR1).isSeparatedFor, hR2⟩
321+
| top => intros ; simpa using Presieve.isSheafFor_top_sieve _
322+
| transitive X R S _ _ H1 H2 =>
323+
intro Y f
324+
simp only [← Presieve.isSeparatedFor_and_exists_isAmalgamation_iff_isSheafFor] at *
325+
choose H1 H1' using H1
326+
choose H2 H2' using H2
327+
refine ⟨?_, fun x hx => ?_⟩
328+
· intro x t₁ t₂ h₁ h₂
329+
refine (H1 f).ext (fun Z g hg => ?_)
330+
refine (H2 hg (𝟙 _)).ext (fun ZZ gg hgg => ?_)
331+
simp only [Sieve.pullback_id, Sieve.pullback_apply] at hgg
332+
simp only [← types_comp_apply]
333+
rw [← P.map_comp, ← op_comp, h₁, h₂]
334+
simpa only [Sieve.pullback_apply, Category.assoc] using hgg
335+
let y : ∀ ⦃Z : C⦄ (g : Z ⟶ Y),
336+
((S.pullback (g ≫ f)).pullback (𝟙 _)).arrows.FamilyOfElements P :=
337+
fun Z g ZZ gg hgg => x (gg ≫ g) (by simpa using hgg)
338+
have hy : ∀ ⦃Z : C⦄ (g : Z ⟶ Y), (y g).Compatible := by
339+
intro Z g Y₁ Y₂ ZZ g₁ g₂ f₁ f₂ h₁ h₂ h
340+
rw [hx]
341+
rw [reassoc_of% h]
342+
choose z hz using fun ⦃Z : C⦄ ⦃g : Z ⟶ Y⦄ (hg : R.pullback f g) =>
343+
H2' hg (𝟙 _) (y g) (hy g)
344+
let q : (R.pullback f).arrows.FamilyOfElements P := fun Z g hg => z hg
345+
have hq : q.Compatible := by
346+
intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ h
347+
apply (H2 h₁ g₁).ext
348+
intro ZZ gg hgg
349+
simp only [← types_comp_apply]
350+
rw [← P.map_comp, ← P.map_comp, ← op_comp, ← op_comp, hz, hz]
351+
· dsimp ; congr 1 ; simp only [Category.assoc, h]
352+
· simpa [reassoc_of% h] using hgg
353+
· simpa using hgg
354+
obtain ⟨t, ht⟩ := H1' f q hq
355+
refine ⟨t, fun Z g hg => ?_⟩
356+
refine (H1 (g ≫ f)).ext (fun ZZ gg hgg => ?_)
357+
rw [← types_comp_apply _ (P.map gg.op), ← P.map_comp, ← op_comp, ht]
358+
swap ; simpa using hgg
359+
refine (H2 hgg (𝟙 _)).ext (fun ZZZ ggg hggg => ?_)
360+
rw [← types_comp_apply _ (P.map ggg.op), ← P.map_comp, ← op_comp, hz]
361+
swap ; simpa using hggg
362+
refine (H2 hgg ggg).ext (fun ZZZZ gggg _ => ?_)
363+
rw [← types_comp_apply _ (P.map gggg.op), ← P.map_comp, ← op_comp]
364+
apply hx
365+
simp
366+
367+
end Presieve
368+
369+
end CategoryTheory

0 commit comments

Comments
 (0)