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

Commit 2241588

Browse files
committed
feat(topology/homotopy): Homotopic maps induce naturally isomorphic functors between fundamental groupoid (#11595)
Co-authored-by: prakol16 <prakol16@users.noreply.github.com>
1 parent 5f3f70f commit 2241588

File tree

5 files changed

+249
-2
lines changed

5 files changed

+249
-2
lines changed

src/category_theory/category/Groupoid.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ instance forget_to_Cat_faithful : faithful forget_to_Cat := { }
7474
which sometimes helps in applying simp lemmas -/
7575
lemma hom_to_functor {C D E : Groupoid.{v u}} (f : C ⟶ D) (g : D ⟶ E) : f ≫ g = f ⋙ g := rfl
7676

77+
/-- Converts identity in the category of groupoids to the functor identity -/
78+
lemma id_to_functor {C : Groupoid.{v u}} : 𝟭 C = 𝟙 C := rfl
79+
7780
section products
7881

7982
/-- The cone for the product of a family of groupoids indexed by J is a limit cone -/

src/topology/homotopy/fundamental_groupoid.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ localized "notation `πₓ` := fundamental_groupoid.fundamental_groupoid_functor
330330
localized "notation `πₘ` := fundamental_groupoid.fundamental_groupoid_functor.map"
331331
in fundamental_groupoid
332332

333+
lemma map_eq {X Y : Top} {x₀ x₁ : X} (f : C(X, Y)) (p : path.homotopic.quotient x₀ x₁) :
334+
(πₘ f).map p = p.map_fn f := rfl
335+
333336
/-- Help the typechecker by converting a point in a groupoid back to a point in
334337
the underlying topological space. -/
335338
@[reducible]
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/-
2+
Copyright (c) 2022 Praneeth Kolichala. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Praneeth Kolichala
5+
-/
6+
import topology.homotopy.product
7+
import topology.homotopy.equiv
8+
import category_theory.equivalence
9+
10+
/-!
11+
# Homotopic maps induce naturally isomorphic functors
12+
13+
## Main definitions
14+
15+
- `fundamental_groupoid_functor.homotopic_maps_nat_iso H` The natural isomorphism
16+
between the induced functors `f : π(X) ⥤ π(Y)` and `g : π(X) ⥤ π(Y)`, given a homotopy
17+
`H : f ∼ g`
18+
19+
- `fundamental_groupoid_functor.equiv_of_homotopy_equiv hequiv` The equivalence of the categories
20+
`π(X)` and `π(Y)` given a homotopy equivalence `hequiv : X ≃ₕ Y` between them.
21+
22+
## Implementation notes
23+
- In order to be more universe polymorphic, we define `continuous_map.homotopy.ulift_map`
24+
which lifts a homotopy from `I × X → Y` to `(Top.of ((ulift I) × X)) → Y`. This is because
25+
this construction uses `fundamental_groupoid_functor.prod_to_prod_Top` to convert between
26+
pairs of paths in I and X and the corresponding path after passing through a homotopy `H`.
27+
But `fundamental_groupoid_functor.prod_to_prod_Top` requires two spaces in the same universe.
28+
-/
29+
30+
noncomputable theory
31+
32+
universe u
33+
34+
open fundamental_groupoid
35+
open category_theory
36+
open fundamental_groupoid_functor
37+
38+
open_locale fundamental_groupoid
39+
open_locale unit_interval
40+
41+
namespace unit_interval
42+
43+
/-- The path 0 ⟶ 1 in I -/
44+
def path01 : path (0 : I) 1 := { to_fun := id, source' := rfl, target' := rfl }
45+
46+
/-- The path 0 ⟶ 1 in ulift I -/
47+
def upath01 : path (ulift.up 0 : ulift.{u} I) (ulift.up 1) :=
48+
{ to_fun := ulift.up, source' := rfl, target' := rfl }
49+
50+
local attribute [instance] path.homotopic.setoid
51+
/-- The homotopy path class of 0 → 1 in `ulift I` -/
52+
def uhpath01 : @from_top (Top.of $ ulift.{u} I) (ulift.up (0 : I)) ⟶ from_top (ulift.up 1) :=
53+
⟦upath01⟧
54+
55+
end unit_interval
56+
57+
namespace continuous_map.homotopy
58+
open unit_interval (uhpath01)
59+
60+
local attribute [instance] path.homotopic.setoid
61+
62+
section casts
63+
64+
/-- Abbreviation for `eq_to_hom` that accepts points in a topological space -/
65+
abbreviation hcast {X : Top} {x₀ x₁ : X} (hx : x₀ = x₁) : from_top x₀ ⟶ from_top x₁ := eq_to_hom hx
66+
67+
@[simp] lemma hcast_def {X : Top} {x₀ x₁ : X} (hx₀ : x₀ = x₁) : hcast hx₀ = eq_to_hom hx₀ := rfl
68+
69+
variables {X₁ X₂ Y : Top.{u}} {f : C(X₁, Y)} {g : C(X₂, Y)}
70+
{x₀ x₁ : X₁} {x₂ x₃ : X₂} {p : path x₀ x₁} {q : path x₂ x₃} (hfg : ∀ t, f (p t) = g (q t))
71+
72+
include hfg
73+
74+
/-- If `f(p(t) = g(q(t))` for two paths `p` and `q`, then the induced path homotopy classes
75+
`f(p)` and `g(p)` are the same as well, despite having a priori different types -/
76+
lemma heq_path_of_eq_image : (πₘ f).map ⟦p⟧ == (πₘ g).map ⟦q⟧ :=
77+
by { simp only [map_eq, ← path.homotopic.map_lift], apply path.homotopic.hpath_hext, exact hfg, }
78+
79+
private lemma start_path : f x₀ = g x₂ := by { convert hfg 0; simp only [path.source], }
80+
private lemma end_path : f x₁ = g x₃ := by { convert hfg 1; simp only [path.target], }
81+
82+
lemma eq_path_of_eq_image :
83+
(πₘ f).map ⟦p⟧ = hcast (start_path hfg) ≫ (πₘ g).map ⟦q⟧ ≫ hcast (end_path hfg).symm :=
84+
by { rw functor.conj_eq_to_hom_iff_heq, exact heq_path_of_eq_image hfg }
85+
86+
end casts
87+
88+
/- We let `X` and `Y` be spaces, and `f` and `g` be homotopic maps between them -/
89+
variables {X Y : Top.{u}} {f g : C(X, Y)} (H : continuous_map.homotopy f g)
90+
{x₀ x₁ : X} (p : from_top x₀ ⟶ from_top x₁)
91+
92+
/-!
93+
These definitions set up the following diagram, for each path `p`:
94+
95+
f(p)
96+
*--------*
97+
| \ |
98+
H₀ | \ d | H₁
99+
| \ |
100+
*--------*
101+
g(p)
102+
103+
Here, `H₀ = H.eval_at x₀` is the path from `f(x₀)` to `g(x₀)`,
104+
and similarly for `H₁`. Similarly, `f(p)` denotes the
105+
path in Y that the induced map `f` takes `p`, and similarly for `g(p)`.
106+
107+
Finally, `d`, the diagonal path, is H(0 ⟶ 1, p), the result of the induced `H` on
108+
`path.homotopic.prod (0 ⟶ 1) p`, where `(0 ⟶ 1)` denotes the path from `0` to `1` in `I`.
109+
110+
It is clear that the diagram commutes (`H₀ ≫ g(p) = d = f(p) ≫ H₁`), but unfortunately,
111+
many of the paths do not have defeq starting/ending points, so we end up needing some casting.
112+
-/
113+
114+
/-- Interpret a homotopy `H : C(I × X, Y) as a map C(ulift I × X, Y) -/
115+
def ulift_map : C(Top.of (ulift.{u} I × X), Y) :=
116+
⟨λ x, H (x.1.down, x.2),
117+
H.continuous.comp ((continuous_induced_dom.comp continuous_fst).prod_mk continuous_snd)⟩
118+
119+
@[simp] lemma ulift_apply (i : ulift.{u} I) (x : X) : H.ulift_map (i, x) = H (i.down, x) := rfl
120+
121+
/-- An abbreviation for `prod_to_prod_Top`, with some types already in place to help the
122+
typechecker. In particular, the first path should be on the ulifted unit interval. -/
123+
abbreviation prod_to_prod_Top_I {a₁ a₂ : Top.of (ulift I)} {b₁ b₂ : X}
124+
(p₁ : from_top a₁ ⟶ from_top a₂) (p₂ : from_top b₁ ⟶ from_top b₂) :=
125+
@category_theory.functor.map _ _ _ _ (prod_to_prod_Top (Top.of $ ulift I) X)
126+
(a₁, b₁) (a₂, b₂) (p₁, p₂)
127+
128+
/-- The diagonal path `d` of a homotopy `H` on a path `p` -/
129+
def diagonal_path : from_top (H (0, x₀)) ⟶ from_top (H (1, x₁)) :=
130+
(πₘ H.ulift_map).map (prod_to_prod_Top_I uhpath01 p)
131+
132+
/-- The diagonal path, but starting from `f x₀` and going to `g x₁` -/
133+
def diagonal_path' : from_top (f x₀) ⟶ from_top (g x₁) :=
134+
hcast (H.apply_zero x₀).symm ≫ (H.diagonal_path p) ≫ hcast (H.apply_one x₁)
135+
136+
/-- Proof that `f(p) = H(0 ⟶ 0, p)`, with the appropriate casts -/
137+
lemma apply_zero_path : (πₘ f).map p = hcast (H.apply_zero x₀).symm ≫
138+
(πₘ H.ulift_map).map (prod_to_prod_Top_I (𝟙 (ulift.up 0)) p) ≫
139+
hcast (H.apply_zero x₁) :=
140+
begin
141+
apply quotient.induction_on p,
142+
intro p',
143+
apply @eq_path_of_eq_image _ _ _ _ H.ulift_map _ _ _ _ _ ((path.refl (ulift.up _)).prod p'),
144+
simp,
145+
end
146+
147+
/-- Proof that `g(p) = H(1 ⟶ 1, p)`, with the appropriate casts -/
148+
lemma apply_one_path : (πₘ g).map p = hcast (H.apply_one x₀).symm ≫
149+
((πₘ H.ulift_map).map (prod_to_prod_Top_I (𝟙 (ulift.up 1)) p)) ≫
150+
hcast (H.apply_one x₁) :=
151+
begin
152+
apply quotient.induction_on p,
153+
intro p',
154+
apply @eq_path_of_eq_image _ _ _ _ H.ulift_map _ _ _ _ _ ((path.refl (ulift.up _)).prod p'),
155+
simp,
156+
end
157+
158+
/-- Proof that `H.eval_at x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
159+
lemma eval_at_eq (x : X) : ⟦H.eval_at x⟧ =
160+
hcast (H.apply_zero x).symm ≫
161+
(πₘ H.ulift_map).map (prod_to_prod_Top_I uhpath01 (𝟙 x)) ≫
162+
hcast (H.apply_one x).symm.symm :=
163+
begin
164+
dunfold prod_to_prod_Top_I uhpath01 hcast,
165+
refine (@functor.conj_eq_to_hom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _ _).mpr _,
166+
simp only [id_eq_path_refl, prod_to_prod_Top_map, path.homotopic.prod_lift, map_eq,
167+
← path.homotopic.map_lift],
168+
apply path.homotopic.hpath_hext, intro, refl,
169+
end
170+
171+
/- Finally, we show `d = f(p) ≫ H₁ = H₀ ≫ g(p)` -/
172+
lemma eq_diag_path :
173+
(πₘ f).map p ≫ ⟦H.eval_at x₁⟧ = H.diagonal_path' p ∧
174+
(⟦H.eval_at x₀⟧ ≫ (πₘ g).map p : from_top (f x₀) ⟶ from_top (g x₁)) = H.diagonal_path' p :=
175+
begin
176+
rw [H.apply_zero_path, H.apply_one_path, H.eval_at_eq, H.eval_at_eq],
177+
dunfold prod_to_prod_Top_I,
178+
split; { slice_lhs 2 5 { simp [← category_theory.functor.map_comp], }, refl, },
179+
end
180+
181+
end continuous_map.homotopy
182+
183+
namespace fundamental_groupoid_functor
184+
open category_theory
185+
open_locale fundamental_groupoid
186+
local attribute [instance] path.homotopic.setoid
187+
188+
variables {X Y : Top.{u}} {f g : C(X, Y)} (H : continuous_map.homotopy f g)
189+
190+
/-- Given a homotopy H : f ∼ g, we have an associated natural isomorphism between the induced
191+
functors `f` and `g` -/
192+
def homotopic_maps_nat_iso : πₘ f ⟶ πₘ g :=
193+
{ app := λ x, ⟦H.eval_at x⟧,
194+
naturality' := λ x y p, by rw [(H.eq_diag_path p).1, (H.eq_diag_path p).2] }
195+
196+
instance : is_iso (homotopic_maps_nat_iso H) := by apply nat_iso.is_iso_of_is_iso_app
197+
198+
open_locale continuous_map
199+
200+
/-- Homotopy equivalent topological spaces have equivalent fundamental groupoids. -/
201+
def equiv_of_homotopy_equiv (hequiv : X ≃ₕ Y) : πₓ X ≌ πₓ Y :=
202+
begin
203+
apply equivalence.mk
204+
(πₘ hequiv.to_fun : πₓ X ⥤ πₓ Y)
205+
(πₘ hequiv.inv_fun : πₓ Y ⥤ πₓ X);
206+
simp only [Groupoid.hom_to_functor, Groupoid.id_to_functor],
207+
{ convert (as_iso (homotopic_maps_nat_iso hequiv.left_inv.some)).symm,
208+
exacts [((π).map_id X).symm, ((π).map_comp _ _).symm] },
209+
{ convert as_iso (homotopic_maps_nat_iso hequiv.right_inv.some),
210+
exacts [((π).map_comp _ _).symm, ((π).map_id Y).symm] },
211+
end
212+
213+
end fundamental_groupoid_functor

src/topology/homotopy/path.lean

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ In this file, we define a `homotopy` between two `path`s. In addition, we define
3333
universes u v
3434

3535
variables {X : Type u} {Y : Type v} [topological_space X] [topological_space Y]
36-
variables {x₀ x₁ x₂ : X}
36+
variables {x₀ x₁ x₂ x₃ : X}
3737

3838
noncomputable theory
3939

@@ -309,6 +309,29 @@ quotient.map (λ (q : path x₀ x₁), q.map f.continuous) (λ p₀ p₁ h, path
309309
lemma map_lift (P₀ : path x₀ x₁) (f : C(X, Y)) :
310310
⟦P₀.map f.continuous⟧ = quotient.map_fn ⟦P₀⟧ f := rfl
311311

312+
lemma hpath_hext {p₁ : path x₀ x₁} {p₂ : path x₂ x₃} (hp : ∀ t, p₁ t = p₂ t) : ⟦p₁⟧ == ⟦p₂⟧ :=
313+
begin
314+
have : x₀ = x₂ := by { convert hp 0; simp, }, subst this,
315+
have : x₁ = x₃ := by { convert hp 1; simp, }, subst this,
316+
rw heq_iff_eq, congr, ext t, exact hp t,
317+
end
318+
319+
312320
end homotopic
313321

314322
end path
323+
324+
325+
namespace continuous_map.homotopy
326+
327+
/--
328+
Given a homotopy H: f ∼ g, get the path traced by the point `x` as it moves from
329+
`f x` to `g x`
330+
-/
331+
def eval_at {X : Type*} {Y : Type*} [topological_space X] [topological_space Y] {f g : C(X, Y)}
332+
(H : continuous_map.homotopy f g) (x : X) : path (f x) (g x) :=
333+
{ to_fun := λ t, H (t, x),
334+
source' := H.apply_zero x,
335+
target' := H.apply_one x, }
336+
337+
end continuous_map.homotopy

src/topology/homotopy/product.lean

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ def proj_right : πₓ (Top.of (A × B)) ⥤ πₓ B := πₘ ⟨_, continuous_s
387387
The map taking the product of two fundamental groupoids to the fundamental groupoid of the product
388388
of the two topological spaces. This is in fact an isomorphism (see `prod_iso`).
389389
-/
390-
@[simps]
390+
@[simps obj]
391391
def prod_to_prod_Top : (πₓ A) × (πₓ B) ⥤ πₓ (Top.of (A × B)) :=
392392
{ obj := λ g, g,
393393
map := λ x y p, match x, y, p with
@@ -404,6 +404,11 @@ def prod_to_prod_Top : (πₓ A) × (πₓ B) ⥤ πₓ (Top.of (A × B)) :=
404404
(path.homotopic.comp_prod_eq_prod_comp f₀ f₁ g₀ g₁).symm
405405
end }
406406

407+
lemma prod_to_prod_Top_map {x₀ x₁ : πₓ A} {y₀ y₁ : πₓ B}
408+
(p₀ : x₀ ⟶ x₁) (p₁ : y₀ ⟶ y₁) :
409+
@category_theory.functor.map _ _ _ _
410+
(prod_to_prod_Top A B) (x₀, y₀) (x₁, y₁) (p₀, p₁) = path.homotopic.prod p₀ p₁ := rfl
411+
407412
/--
408413
Shows `prod_to_prod_Top` is an isomorphism, whose inverse is precisely the product
409414
of the induced left and right projections.

0 commit comments

Comments
 (0)