Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 3df0f77

Browse files
feat(topology/sheaves): Induced map on stalks (#7092)
This PR defines stalk maps for morphisms of presheaves. We prove that a morphism of type-valued sheaves is an isomorphism if and only if all the stalk maps are isomorphisms. A few more lemmas about unique gluing are also added, as well as docstrings.
1 parent 98c483b commit 3df0f77

File tree

3 files changed

+256
-8
lines changed

3 files changed

+256
-8
lines changed

src/topology/sheaves/sheaf_condition/equalizer_products.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ are given by the restriction maps from `U j` to `U i ⊓ U j`.
6767
def res : F.obj (op (supr U)) ⟶ pi_opens F U :=
6868
pi.lift (λ i : ι, F.map (topological_space.opens.le_supr U i).op)
6969

70+
@[simp] lemma res_π (i : ι) : res F U ≫ limit.π _ i = F.map (opens.le_supr U i).op :=
71+
by rw [res, limit.lift_π, fan.mk_π_app]
72+
7073
lemma w : res F U ≫ left_res F U = res F U ≫ right_res F U :=
7174
begin
7275
dsimp [res, left_res, right_res],

src/topology/sheaves/sheaf_condition/unique_gluing.lean

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authors: Justus Springer
55
-/
66
import topology.sheaves.sheaf
77
import category_theory.limits.shapes.types
8+
import category_theory.types
89

910
/-!
1011
# The sheaf condition for a type-valued presheaf
@@ -43,6 +44,11 @@ namespace presheaf
4344

4445
variables {X : Top.{u}} (F : presheaf (Type u) X) {ι : Type u} (U : ι → opens X)
4546

47+
@[simp] lemma res_π_apply (i : ι) (s : F.obj (op (supr U))) :
48+
limit.π (discrete.functor (λ i : ι, F.obj (op (U i)))) i (res F U s) =
49+
F.map (opens.le_supr U i).op s :=
50+
congr_fun (res_π F U i) s
51+
4652
/--
4753
A family of sections `sf` is compatible, if the restrictions of `sf i` and `sf j` to `U i ⊓ U j`
4854
agree, for all `i` and `j`
@@ -177,8 +183,7 @@ def sheaf_condition_unique_gluing_of_sheaf_condition :
177183
choose gl gl_spec gl_uniq using types.unique_of_type_equalizer _ _ (Fsh U) sf' hsf',
178184
refine eq.trans (gl_uniq s.1 _) (gl_uniq t.1 _).symm ;
179185
rw [← is_gluing_iff_eq_res F U _ _, inv_hom_id_apply],
180-
{ exact s.2 },
181-
{ exact t.2 }
186+
exacts [s.2, t.2]
182187
end
183188
}
184189

@@ -211,8 +216,7 @@ sheaf_condition_of_sheaf_condition_unique_gluing F $ λ ι U sf hsf,
211216
ext,
212217
choose gl gl_spec gl_uniq using h U sf hsf,
213218
refine eq.trans (gl_uniq s.1 _) (gl_uniq t.1 _).symm,
214-
{ exact s.2 },
215-
{ exact t.2 }
219+
exacts [s.2, t.2]
216220
},
217221
}
218222

@@ -221,22 +225,72 @@ end presheaf
221225

222226
namespace sheaf
223227
open presheaf
228+
open category_theory
224229

225230
variables {X : Top.{u}} (F : sheaf (Type u) X) {ι : Type u} (U : ι → opens X)
226231

227232
/--
228233
A more convenient way of obtaining a unique gluing of sections for a sheaf
229234
-/
230235
lemma exists_unique_gluing (sf : Π i : ι, F.presheaf.obj (op (U i)))
231-
(hsf : is_compatible F.presheaf U sf) :
232-
∃! s : F.presheaf.obj (op (supr U)), is_gluing F.presheaf U sf s :=
236+
(h : is_compatible F.presheaf U sf ) :
237+
∃! s : F.presheaf.obj (op (supr U)), is_gluing F.presheaf U sf s :=
233238
begin
234-
have := (sheaf_condition_unique_gluing_of_sheaf_condition _ F.sheaf_condition U sf hsf),
239+
have := (sheaf_condition_unique_gluing_of_sheaf_condition _ F.sheaf_condition U sf h),
235240
refine ⟨this.default.1,this.default.2,_⟩,
236241
intros s hs,
237242
exact congr_arg subtype.val (this.uniq ⟨s,hs⟩),
238243
end
239244

245+
/--
246+
In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
247+
which can be more convenient in practice.
248+
-/
249+
lemma exists_unique_gluing' (V : opens X) (iUV : Π i : ι, U i ⟶ V) (hcover : V ≤ supr U)
250+
(sf : Π i : ι, F.presheaf.obj (op (U i))) (h : is_compatible F.presheaf U sf) :
251+
∃! s : F.presheaf.obj (op V), ∀ i : ι, F.presheaf.map (iUV i).op s = sf i :=
252+
begin
253+
have V_eq_supr_U : V = supr U := le_antisymm hcover (supr_le (λ i, le_of_hom (iUV i))),
254+
obtain ⟨gl, gl_spec, gl_uniq⟩ := F.exists_unique_gluing U sf h,
255+
refine ⟨F.presheaf.map (eq_to_hom V_eq_supr_U).op gl, (λ i,_), (λ gl' gl'_spec,_)⟩,
256+
{ rw ← functor_to_types.map_comp_apply,
257+
exact gl_spec i },
258+
{ convert congr_arg _ (gl_uniq (F.presheaf.map (eq_to_hom V_eq_supr_U.symm).op gl') (λ i,_)) ;
259+
rw ← functor_to_types.map_comp_apply,
260+
{ exact (functor_to_types.map_id_apply _ _).symm },
261+
{ convert gl'_spec i }}
262+
end
263+
264+
@[ext]
265+
lemma eq_of_locally_eq (s t : F.presheaf.obj (op (supr U)))
266+
(h : ∀ i, F.presheaf.map (opens.le_supr U i).op s = F.presheaf.map (opens.le_supr U i).op t) :
267+
s = t :=
268+
begin
269+
apply (mono_iff_injective _).mp (mono_of_is_limit_parallel_pair (F.sheaf_condition U)),
270+
ext,
271+
simp only [fork_ι, res_π_apply, h],
272+
end
273+
274+
/--
275+
In this version of the lemma, the inclusion homs `iUV` can be specified directly by the user,
276+
which can be more convenient in practice.
277+
-/
278+
lemma eq_of_locally_eq' (V : opens X) (iUV : Π i : ι, U i ⟶ V) (hcover : V ≤ supr U)
279+
(s t : F.presheaf.obj (op V))
280+
(h : ∀ i, F.presheaf.map (iUV i).op s = F.presheaf.map (iUV i).op t) : s = t :=
281+
begin
282+
have V_eq_supr_U : V = supr U := le_antisymm hcover (supr_le (λ i, le_of_hom (iUV i))),
283+
suffices : F.presheaf.map (eq_to_hom V_eq_supr_U.symm).op s =
284+
F.presheaf.map (eq_to_hom V_eq_supr_U.symm).op t,
285+
{ convert congr_arg (F.presheaf.map (eq_to_hom V_eq_supr_U).op) this ;
286+
rw ← functor_to_types.map_comp_apply ;
287+
exact (functor_to_types.map_id_apply _ _).symm },
288+
apply eq_of_locally_eq,
289+
intro i,
290+
rw [← functor_to_types.map_comp_apply, ← functor_to_types.map_comp_apply],
291+
convert h i
292+
end
293+
240294
end sheaf
241295

242296
end Top

src/topology/sheaves/stalks.lean

Lines changed: 192 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,35 @@
11
/-
22
Copyright (c) 2019 Scott Morrison. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Scott Morrison
4+
Authors: Scott Morrison, Justus Springer
55
-/
66
import topology.category.Top.open_nhds
77
import topology.sheaves.presheaf
8+
import topology.sheaves.sheaf_condition.unique_gluing
89
import category_theory.limits.types
910

11+
/-!
12+
# Stalks
13+
14+
For a presheaf `F` on a topological space `X`, valued in some category `C`, the *stalk* of `F`
15+
at the point `x : X` is defined as the colimit of the following functor
16+
17+
(nhds x)ᵒᵖ ⥤ (opens X)ᵒᵖ ⥤ C
18+
19+
where the functor on the left is the inclusion of categories and the functor on the right is `F`.
20+
For an open neighborhood `U` of `x`, we define the map `F.germ x : F.obj (op U) ⟶ F.stalk x` as the
21+
canonical morphism into this colimit.
22+
23+
Taking stalks is functorial: For every point `x : X` we define a functor `stalk_functor C x`,
24+
sending presheaves on `X` to objects of `C`. In `is_iso_iff_stalk_functor_map_iso`, we prove that a
25+
map `f : F ⟶ G` between `Type`-valued sheaves is an isomorphism if and only if all the maps
26+
`F.stalk x ⟶ G.stalk x` (given by the stalk functor on `f`) are isomorphisms.
27+
28+
For a map `f : X ⟶ Y` between topological spaces, we define `stalk_pushforward` as the induced map
29+
on the stalks `(f _* ℱ).stalk (f x) ⟶ ℱ.stalk x`.
30+
31+
-/
32+
1033
noncomputable theory
1134

1235
universes v u v' u'
@@ -109,6 +132,173 @@ lemma stalk_hom_ext (F : X.presheaf C) {x} {Y : C} {f₁ f₂ : F.stalk x ⟶ Y}
109132
(ih : ∀ (U : opens X) (hxU : x ∈ U), F.germ ⟨x, hxU⟩ ≫ f₁ = F.germ ⟨x, hxU⟩ ≫ f₂) : f₁ = f₂ :=
110133
colimit.hom_ext $ λ U, by { op_induction U, cases U with U hxU, exact ih U hxU }
111134

135+
/-- If two sections agree on all stalks, they must be equal -/
136+
lemma section_ext (F : sheaf (Type v) X) (U : opens X) (s t : F.presheaf.obj (op U)) :
137+
(∀ x : U, F.presheaf.germ x s = F.presheaf.germ x t) → s = t :=
138+
begin
139+
intro h,
140+
-- We use `germ_eq` and the axiom of choice, to pick for every point `x` a neighbourhood
141+
-- `V`, such that the restrictions of `s` and `t` to `V` coincide. Since a restriction
142+
-- map `V ⟶ U` is *data* (lives in `Type`, not `Prop`), we encode all of this as a dependent
143+
-- pair (sigma type)
144+
let V : Π (x : U), Σ (V : open_nhds x.1),
145+
{ iVU : V.1 ⟶ U // F.presheaf.map iVU.op s = F.presheaf.map iVU.op t } := λ x, by {
146+
choose V m iVU₀ iVU₁ heq using (F.presheaf.germ_eq x.1 x.2 x.2 s t (h x)),
147+
refine ⟨⟨V,m⟩,iVU₀,_⟩,
148+
convert heq,
149+
},
150+
refine F.eq_of_locally_eq' (λ x, (V x).1.1) U (λ x, (V x).2.1) _ s t (λ x, (V x).2.2),
151+
-- Here, it remains to show that the choosen neighborhoods really define a cover of `U`
152+
intros x hxU,
153+
rw [subtype.val_eq_coe, opens.mem_coe, opens.mem_supr],
154+
exact ⟨⟨x,hxU⟩,(V ⟨x,hxU⟩).1.2⟩,
155+
end
156+
157+
@[simp, reassoc] lemma stalk_functor_map_germ {F G : X.presheaf C} (U : opens X) (x : U)
158+
(f : F ⟶ G) : germ F x ≫ (stalk_functor C x.1).map f = f.app (op U) ≫ germ G x :=
159+
colimit.ι_map (whisker_left ((open_nhds.inclusion x.1).op) f) (op ⟨U, x.2⟩)
160+
161+
@[simp] lemma stalk_functor_map_germ_apply (U : opens X) (x : U) {F G : X.presheaf (Type v)}
162+
(f : F ⟶ G) (s : F.obj (op U)) :
163+
(stalk_functor (Type v) x.1).map f (germ F x s) = germ G x (f.app (op U) s) :=
164+
congr_fun (stalk_functor_map_germ U x f) s
165+
166+
open function
167+
168+
lemma stalk_functor_map_injective_of_app_injective {F G : presheaf (Type v) X} (f : F ⟶ G)
169+
(h : ∀ U : opens X, injective (f.app (op U))) (x : X) :
170+
injective ((stalk_functor (Type v) x).map f) := λ s t hst,
171+
begin
172+
rcases germ_exist F x s with ⟨U₁, hxU₁, s, rfl⟩,
173+
rcases germ_exist F x t with ⟨U₂, hxU₂, t, rfl⟩,
174+
simp only [stalk_functor_map_germ_apply _ ⟨x,_⟩] at hst,
175+
obtain ⟨W, hxW, iWU₁, iWU₂, heq⟩ := G.germ_eq x hxU₁ hxU₂ _ _ hst,
176+
rw [← functor_to_types.naturality, ← functor_to_types.naturality] at heq,
177+
replace heq := h W heq,
178+
convert congr_arg (F.germ ⟨x,hxW⟩) heq,
179+
exacts [(F.germ_res_apply iWU₁ ⟨x,hxW⟩ s).symm,
180+
(F.germ_res_apply iWU₂ ⟨x,hxW⟩ t).symm],
181+
end
182+
183+
/-
184+
Note that the analogous statement for surjectivity is false: Surjectivity on stalks does not
185+
imply surjectivity of the components of a sheaf morphism. However it does imply that the morphism
186+
is an epi, but this fact is not yet formalized.
187+
-/
188+
lemma app_injective_of_stalk_functor_map_injective {F : sheaf (Type v) X} {G : presheaf (Type v) X}
189+
(f : F.presheaf ⟶ G) (h : ∀ x : X, injective ((stalk_functor (Type v) x).map f)) (U : opens X) :
190+
injective (f.app (op U)) := λ s t hst,
191+
begin
192+
apply section_ext,
193+
intro x,
194+
apply h x.1,
195+
simp only [stalk_functor_map_germ_apply, hst],
196+
end
197+
198+
lemma app_injective_iff_stalk_functor_map_injective {F : sheaf (Type v) X}
199+
{G : presheaf (Type v) X} (f : F.presheaf ⟶ G) :
200+
(∀ x : X, injective ((stalk_functor (Type v) x).map f)) ↔
201+
(∀ U : opens X, injective (f.app (op U))) :=
202+
⟨app_injective_of_stalk_functor_map_injective f, stalk_functor_map_injective_of_app_injective f⟩
203+
204+
lemma app_bijective_of_stalk_functor_map_bijective {F G : sheaf (Type v) X} (f : F ⟶ G)
205+
(h : ∀ x : X, bijective ((stalk_functor (Type v) x).map f)) (U : opens X) :
206+
bijective (f.app (op U)) :=
207+
begin
208+
-- We already know that `f.app (op U)` is injective. We save that fact here as we will
209+
-- need it again later.
210+
have h_inj := app_injective_of_stalk_functor_map_injective f (λ x, (h x).1),
211+
refine ⟨h_inj U, (λ t,_)⟩,
212+
-- For surjectivity, we are given an arbitrary section `t` and need to find a preimage for it.
213+
-- First, we show that we can find preimages *locally*. That is, for each `x : U` we construct
214+
-- neighborhood `V ≤ U` and a section `s : F.obj (op V))` such that `f.app (op V) s` and `t`
215+
-- agree on `V`.
216+
have exists_local_preim : ∀ x : U, ∃ (V : open_nhds x.1) (iVU : V.1 ⟶ U)
217+
(s : F.presheaf.obj (op V.1)), f.app (op V.1) s = G.presheaf.map iVU.op t := λ x, by {
218+
-- Since `f` is surjective on stalks, we can find a preimage `s₀` of the germ of `t`
219+
obtain ⟨s₀,hs₀⟩ := (h x).2 (G.presheaf.germ x t),
220+
-- ... and this preimage must come from some section `s₁`
221+
obtain ⟨V₁,hxV₁,s₁,hs₁⟩ := F.presheaf.germ_exist x.1 s₀,
222+
subst hs₁, rename hs₀ hs₁,
223+
erw stalk_functor_map_germ_apply V₁ ⟨x.1,hxV₁⟩ f s₁ at hs₁,
224+
-- Now, the germ of `f.app (op V₁) s₁` equals the germ of `t`, hence they must coincide on
225+
-- some open neighborhood
226+
obtain ⟨V₂,hxV₂, iV₂V₁, iV₂U, heq⟩ := G.presheaf.germ_eq x.1 hxV₁ x.2 _ _ hs₁,
227+
-- The restriction of `s₁` to that neighborhood is our desired local preimage
228+
let s₂ := F.presheaf.map iV₂V₁.op s₁,
229+
use [V₂,hxV₂,iV₂U,s₂],
230+
rwa functor_to_types.naturality },
231+
-- Now, we use the axiom of choice to create a function `local_preim` giving us for each point
232+
-- `x : U` a neighborhood `V` and a local preimage for `t` on `V`.
233+
have local_preim : Π x : U, Σ (V : open_nhds x.1) (iVU : V.1 ⟶ U),
234+
{s : F.presheaf.obj (op V.1) // f.app (op V.1) s = G.presheaf.map iVU.op t } := λ x, by {
235+
choose V iVU s heq using exists_local_preim x,
236+
exact ⟨V,iVU,s,heq⟩ },
237+
clear exists_local_preim,
238+
-- In particular, we obtain a covering family of opens and a family of sections
239+
let V : U → opens X := λ x, (local_preim x).1.1,
240+
let sf : Π x : U, F.presheaf.obj (op (V x)) := λ x, (local_preim x).2.2.1,
241+
have V_cover : U ≤ supr V := λ x hx, by {
242+
rw [subtype.val_eq_coe, opens.mem_coe, opens.mem_supr],
243+
exact ⟨⟨x,hx⟩,(local_preim _).1.2⟩ },
244+
-- Using this data, we can glue all of the local preimages together, giving us our candidate
245+
-- for the preimage of `t`
246+
obtain ⟨s, s_spec, -⟩ := F.exists_unique_gluing' V U (λ x, (local_preim x).2.1) V_cover sf _,
247+
use s,
248+
-- Note that we generated an additional goal: We need to show that our family of sections `sf`
249+
-- is actually compatible. We get that out of the way first.
250+
swap,
251+
{ intros x y,
252+
-- The only thing we know about the sections `sf` is that their image under `f` equals (the
253+
-- restriction of) `t`. It is at this point that we need injectivity of `f` again!
254+
apply h_inj,
255+
-- Here, both sides are equal to a restriction of `t`
256+
transitivity ;
257+
erw [functor_to_types.naturality, (local_preim _).2.2.2, ← functor_to_types.map_comp_apply],
258+
refl },
259+
-- The only thing left to prove is that `s` really is a preimage of `t`
260+
-- Of course, we show the equality locally
261+
apply G.eq_of_locally_eq' V U (λ x, (local_preim x).2.1) V_cover,
262+
intro x,
263+
convert congr_arg (f.app (op (V x))) (s_spec x),
264+
exacts [(functor_to_types.naturality _ _ f _ _).symm, (local_preim x).2.2.2.symm],
265+
end
266+
267+
/--
268+
If all the stalk maps of map `f : F ⟶ G` of `Type`-valued sheaves are isomorphisms, then `f` is
269+
an isomorphism.
270+
-/
271+
-- Making this an instance would cause a loop in typeclass resolution with `functor.map_is_iso`
272+
lemma is_iso_of_stalk_functor_map_iso {F G : sheaf (Type v) X} (f : F ⟶ G)
273+
[∀ x : X, is_iso ((stalk_functor (Type v) x).map f)] : is_iso f :=
274+
begin
275+
-- Rather annoyingly, an isomorphism of presheaves isn't quite the same as an isomorphism of
276+
-- sheaves. We have to use that the induced functor from sheaves to presheaves is fully faithful
277+
haveI : is_iso ((induced_functor sheaf.presheaf).map f) :=
278+
@nat_iso.is_iso_of_is_iso_app _ _ _ _ F.presheaf G.presheaf f (by {
279+
intro U, op_induction U,
280+
rw is_iso_iff_bijective,
281+
exact app_bijective_of_stalk_functor_map_bijective f
282+
(λ x, (is_iso_iff_bijective _).mp (_inst_3 x)) U,
283+
}),
284+
exact is_iso_of_fully_faithful (induced_functor sheaf.presheaf) f,
285+
end
286+
287+
/--
288+
A morphism of `Type`-valued sheaves `f : F ⟶ G` is an isomorphism if and only if all the stalk
289+
maps are isomorphisms
290+
-/
291+
lemma is_iso_iff_stalk_functor_map_iso {F G : sheaf (Type v) X} (f : F ⟶ G) :
292+
is_iso f ↔ ∀ x : X, is_iso ((stalk_functor (Type v) x).map f) :=
293+
begin
294+
split,
295+
{ intros h x, resetI,
296+
exact @functor.map_is_iso _ _ _ _ _ _ (stalk_functor (Type v) x) f
297+
((induced_functor sheaf.presheaf).map_is_iso f) },
298+
{ intro h, resetI,
299+
exact is_iso_of_stalk_functor_map_iso f }
300+
end
301+
112302
variables (C)
113303

114304
def stalk_pushforward (f : X ⟶ Y) (ℱ : X.presheaf C) (x : X) : (f _* ℱ).stalk (f x) ⟶ ℱ.stalk x :=
@@ -174,4 +364,5 @@ begin
174364
end
175365

176366
end stalk_pushforward
367+
177368
end Top.presheaf

0 commit comments

Comments
 (0)