Skip to content

Commit 76f52eb

Browse files
committed
feat(AlgebraicTopology/SimplicialSet): paths and the strict segal condition (#18499)
A path in a simplicial set `X` of length `n` is a directed path comprised of `n` 1-simplices. An `n`-simplex has a maximal path, the `spine` of the simplex, which is a path of length `n`. A simplicial set `X` satisfies the `StrictSegal` condition if for all `n`, the map `X.spine n : X _[n] → X.Path n` is a bijection. Examples of `StrictSegal` simplicial sets are given by nerves of categories. Future work will show these are the only examples: that a `StrictSegal` simplicial set is isomorphic to the nerve of its homotopy category. Co-Authored-By: [Mario Carneiro](https://github.com/digama0) and [Joël Riou](https://github.com/joelriou)
1 parent 579a434 commit 76f52eb

File tree

5 files changed

+299
-0
lines changed

5 files changed

+299
-0
lines changed

Mathlib.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,9 @@ import Mathlib.AlgebraicTopology.SimplicialSet.Basic
10001000
import Mathlib.AlgebraicTopology.SimplicialSet.KanComplex
10011001
import Mathlib.AlgebraicTopology.SimplicialSet.Monoidal
10021002
import Mathlib.AlgebraicTopology.SimplicialSet.Nerve
1003+
import Mathlib.AlgebraicTopology.SimplicialSet.Path
10031004
import Mathlib.AlgebraicTopology.SimplicialSet.Quasicategory
1005+
import Mathlib.AlgebraicTopology.SimplicialSet.StrictSegal
10041006
import Mathlib.AlgebraicTopology.SingularSet
10051007
import Mathlib.AlgebraicTopology.SplitSimplicialObject
10061008
import Mathlib.AlgebraicTopology.TopologicalSimplex

Mathlib/AlgebraicTopology/SimplexCategory.lean

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Copyright (c) 2020 Kim Morrison. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Johan Commelin, Kim Morrison, Adam Topaz
55
-/
6+
import Mathlib.Tactic.FinCases
67
import Mathlib.Tactic.Linarith
78
import Mathlib.CategoryTheory.Skeletal
89
import Mathlib.Data.Fintype.Sort
@@ -168,6 +169,10 @@ theorem const_fac_thru_zero (n m : SimplexCategory) (i : Fin (m.len + 1)) :
168169
const n m i = const n [0] 0 ≫ SimplexCategory.const [0] m i := by
169170
rw [const_comp]; rfl
170171

172+
theorem Hom.ext_zero_left {n : SimplexCategory} (f g : ([0] : SimplexCategory) ⟶ n)
173+
(h0 : f.toOrderHom 0 = g.toOrderHom 0 := by rfl) : f = g := by
174+
ext i; match i with | 0 => exact h0 ▸ rfl
175+
171176
theorem eq_const_of_zero {n : SimplexCategory} (f : ([0] : SimplexCategory) ⟶ n) :
172177
f = const _ n (f.toOrderHom 0) := by
173178
ext x; match x with | 0 => rfl
@@ -180,6 +185,14 @@ theorem eq_const_to_zero {n : SimplexCategory} (f : n ⟶ [0]) :
180185
ext : 3
181186
apply @Subsingleton.elim (Fin 1)
182187

188+
theorem Hom.ext_one_left {n : SimplexCategory} (f g : ([1] : SimplexCategory) ⟶ n)
189+
(h0 : f.toOrderHom 0 = g.toOrderHom 0 := by rfl)
190+
(h1 : f.toOrderHom 1 = g.toOrderHom 1 := by rfl) : f = g := by
191+
ext i
192+
match i with
193+
| 0 => exact h0 ▸ rfl
194+
| 1 => exact h1 ▸ rfl
195+
183196
theorem eq_of_one_to_one (f : ([1] : SimplexCategory) ⟶ [1]) :
184197
(∃ a, f = const [1] _ a) ∨ f = 𝟙 _ := by
185198
match e0 : f.toOrderHom 0, e1 : f.toOrderHom 1 with
@@ -218,6 +231,14 @@ def mkOfLe {n} (i j : Fin (n+1)) (h : i ≤ j) : ([1] : SimplexCategory) ⟶ [n]
218231
| 0, 1, _ => h
219232
}
220233

234+
/-- The morphism `[1] ⟶ [n]` that picks out the "diagonal composite" edge-/
235+
def diag (n : ℕ) : ([1] : SimplexCategory) ⟶ [n] :=
236+
mkOfLe 0 n (Fin.zero_le _)
237+
238+
/-- The morphism `[1] ⟶ [n]` that picks out the edge spanning the interval from `j` to `j + l`.-/
239+
def intervalEdge {n} (j l : ℕ) (hjl : j + l ≤ n) : ([1] : SimplexCategory) ⟶ [n] :=
240+
mkOfLe ⟨j, (by omega)⟩ ⟨j + l, (by omega)⟩ (Nat.le_add_right j l)
241+
221242
/-- The morphism `[1] ⟶ [n]` that picks out the arrow `i ⟶ i+1` in `Fin (n+1)`.-/
222243
def mkOfSucc {n} (i : Fin n) : ([1] : SimplexCategory) ⟶ [n] :=
223244
SimplexCategory.mkHom {
@@ -227,6 +248,15 @@ def mkOfSucc {n} (i : Fin n) : ([1] : SimplexCategory) ⟶ [n] :=
227248
| 0, 1, _ => Fin.castSucc_le_succ i
228249
}
229250

251+
@[simp]
252+
lemma mkOfSucc_homToOrderHom_zero {n} (i : Fin n) :
253+
DFunLike.coe (F := Fin 2 →o Fin (n+1)) (Hom.toOrderHom (mkOfSucc i)) 0 = i.castSucc := rfl
254+
255+
@[simp]
256+
lemma mkOfSucc_homToOrderHom_one {n} (i : Fin n) :
257+
DFunLike.coe (F := Fin 2 →o Fin (n+1)) (Hom.toOrderHom (mkOfSucc i)) 1 = i.succ := rfl
258+
259+
230260
/-- The morphism `[2] ⟶ [n]` that picks out a specified composite of morphisms in `Fin (n+1)`.-/
231261
def mkOfLeComp {n} (i j k : Fin (n + 1)) (h₁ : i ≤ j) (h₂ : j ≤ k) :
232262
([2] : SimplexCategory) ⟶ [n] :=
@@ -239,6 +269,60 @@ def mkOfLeComp {n} (i j k : Fin (n + 1)) (h₁ : i ≤ j) (h₂ : j ≤ k) :
239269
| 0, 2, _ => Fin.le_trans h₁ h₂
240270
}
241271

272+
/-- The "inert" morphism associated to a subinterval `j ≤ i ≤ j + l` of `Fin (n + 1)`.-/
273+
def subinterval {n} (j l : ℕ) (hjl : j + l ≤ n) :
274+
([l] : SimplexCategory) ⟶ [n] :=
275+
SimplexCategory.mkHom {
276+
toFun := fun i => ⟨i.1 + j, (by omega)⟩
277+
monotone' := fun i i' hii' => by simpa only [Fin.mk_le_mk, add_le_add_iff_right] using hii'
278+
}
279+
280+
lemma const_subinterval_eq {n} (j l : ℕ) (hjl : j + l ≤ n) (i : Fin (l + 1)) :
281+
[0].const [l] i ≫ subinterval j l hjl =
282+
[0].const [n] ⟨j + i.1, lt_add_of_lt_add_right (Nat.add_lt_add_left i.2 j) hjl⟩ := by
283+
rw [const_comp]
284+
congr
285+
ext
286+
dsimp [subinterval]
287+
rw [add_comm]
288+
289+
@[simp]
290+
lemma mkOfSucc_subinterval_eq {n} (j l : ℕ) (hjl : j + l ≤ n) (i : Fin l) :
291+
mkOfSucc i ≫ subinterval j l hjl =
292+
mkOfSucc ⟨j + i.1, Nat.lt_of_lt_of_le (Nat.add_lt_add_left i.2 j) hjl⟩ := by
293+
unfold subinterval mkOfSucc
294+
ext i
295+
match i with
296+
| 0 =>
297+
simp only [len_mk, Nat.reduceAdd, mkHom, comp_toOrderHom, Hom.toOrderHom_mk,
298+
OrderHom.mk_comp_mk, Fin.isValue, OrderHom.coe_mk, Function.comp_apply, Fin.castSucc_mk,
299+
Fin.succ_mk]
300+
rw [add_comm]
301+
rfl
302+
| 1 =>
303+
simp only [len_mk, Nat.reduceAdd, mkHom, comp_toOrderHom, Hom.toOrderHom_mk,
304+
OrderHom.mk_comp_mk, Fin.isValue, OrderHom.coe_mk, Function.comp_apply, Fin.castSucc_mk,
305+
Fin.succ_mk]
306+
rw [← Nat.add_comm j _]
307+
rfl
308+
309+
@[simp]
310+
lemma diag_subinterval_eq {n} (j l : ℕ) (hjl : j + l ≤ n) :
311+
diag l ≫ subinterval j l hjl = intervalEdge j l hjl := by
312+
unfold subinterval intervalEdge diag mkOfLe
313+
ext i
314+
match i with
315+
| 0 =>
316+
simp only [len_mk, Nat.reduceAdd, mkHom, Fin.natCast_eq_last, comp_toOrderHom,
317+
Hom.toOrderHom_mk, OrderHom.mk_comp_mk, Fin.isValue, OrderHom.coe_mk, Function.comp_apply]
318+
rw [Nat.add_comm]
319+
rfl
320+
| 1 =>
321+
simp only [len_mk, Nat.reduceAdd, mkHom, Fin.natCast_eq_last, comp_toOrderHom,
322+
Hom.toOrderHom_mk, OrderHom.mk_comp_mk, Fin.isValue, OrderHom.coe_mk, Function.comp_apply]
323+
rw [Nat.add_comm]
324+
rfl
325+
242326
instance (Δ : SimplexCategory) : Subsingleton (Δ ⟶ [0]) where
243327
allEq f g := by ext : 3; apply Subsingleton.elim (α := Fin 1)
244328

@@ -466,6 +550,19 @@ lemma factor_δ_spec {m n : ℕ} (f : ([m] : SimplexCategory) ⟶ [n+1]) (j : Fi
466550
· rwa [succ_le_castSucc_iff, lt_pred_iff]
467551
rw [succ_pred]
468552

553+
@[simp]
554+
lemma δ_zero_mkOfSucc {n : ℕ} (i : Fin n) :
555+
δ 0 ≫ mkOfSucc i = SimplexCategory.const _ [n] i.succ := by
556+
ext x
557+
fin_cases x
558+
rfl
559+
560+
@[simp]
561+
lemma δ_one_mkOfSucc {n : ℕ} (i : Fin n) :
562+
δ 1 ≫ mkOfSucc i = SimplexCategory.const _ _ i.castSucc := by
563+
ext x
564+
fin_cases x
565+
aesop
469566

470567
theorem eq_of_one_to_two (f : ([1] : SimplexCategory) ⟶ [2]) :
471568
f = (δ (n := 1) 0) ∨ f = (δ (n := 1) 1) ∨ f = (δ (n := 1) 2) ∨

Mathlib/AlgebraicTopology/SimplicialObject.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ def δ {n} (i : Fin (n + 2)) : X _[n + 1] ⟶ X _[n] :=
8888
def σ {n} (i : Fin (n + 1)) : X _[n] ⟶ X _[n + 1] :=
8989
X.map (SimplexCategory.σ i).op
9090

91+
/-- The diagonal of a simplex is the long edge of the simplex.-/
92+
def diagonal {n : ℕ} : X _[n] ⟶ X _[1] := X.map ((SimplexCategory.diag n).op)
93+
9194
/-- Isomorphisms from identities in ℕ. -/
9295
def eqToIso {n m : ℕ} (h : n = m) : X _[n] ≅ X _[m] :=
9396
X.mapIso (CategoryTheory.eqToIso (by congr))
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/-
2+
Copyright (c) 2024 Emily Riehl. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Mario Carneiro, Emily Riehl, Joël Riou
5+
-/
6+
import Mathlib.AlgebraicTopology.SimplicialSet.Basic
7+
8+
/-!
9+
# Paths in simplicial sets
10+
11+
A path in a simplicial set `X` of length `n` is a directed path comprised of `n + 1` 0-simplices
12+
and `n` 1-simplices, together with identifications between 0-simplices and the sources and targets
13+
of the 1-simplices.
14+
15+
An `n`-simplex has a maximal path, the `spine` of the simplex, which is a path of length `n`.
16+
-/
17+
18+
universe v u
19+
20+
namespace SSet
21+
22+
open CategoryTheory
23+
24+
open Simplicial SimplexCategory
25+
26+
variable (X : SSet.{u})
27+
28+
/-- A path in a simplicial set `X` of length `n` is a directed path of `n` edges.-/
29+
@[ext]
30+
structure Path (n : ℕ) where
31+
/-- A path includes the data of `n+1` 0-simplices in `X`.-/
32+
vertex (i : Fin (n + 1)) : X _[0]
33+
/-- A path includes the data of `n` 1-simplices in `X`.-/
34+
arrow (i : Fin n) : X _[1]
35+
/-- The sources of the 1-simplices in a path are identified with appropriate 0-simplices.-/
36+
arrow_src (i : Fin n) : X.δ 1 (arrow i) = vertex i.castSucc
37+
/-- The targets of the 1-simplices in a path are identified with appropriate 0-simplices.-/
38+
arrow_tgt (i : Fin n) : X.δ 0 (arrow i) = vertex i.succ
39+
40+
41+
variable {X} in
42+
/-- For `j + l ≤ n`, a path of length `n` restricts to a path of length `l`, namely the subpath
43+
spanned by the vertices `j ≤ i ≤ j + l` and edges `j ≤ i < j + l`. -/
44+
def Path.interval {n : ℕ} (f : Path X n) (j l : ℕ) (hjl : j + l ≤ n) :
45+
Path X l where
46+
vertex i := f.vertex ⟨j + i, by omega⟩
47+
arrow i := f.arrow ⟨j + i, by omega⟩
48+
arrow_src i := f.arrow_src ⟨j + i, by omega⟩
49+
arrow_tgt i := f.arrow_tgt ⟨j + i, by omega⟩
50+
51+
/-- The spine of an `n`-simplex in `X` is the path of edges of length `n` formed by
52+
traversing through its vertices in order.-/
53+
@[simps]
54+
def spine (n : ℕ) (Δ : X _[n]) : X.Path n where
55+
vertex i := X.map (SimplexCategory.const [0] [n] i).op Δ
56+
arrow i := X.map (SimplexCategory.mkOfSucc i).op Δ
57+
arrow_src i := by
58+
dsimp [SimplicialObject.δ]
59+
simp only [← FunctorToTypes.map_comp_apply, ← op_comp]
60+
rw [SimplexCategory.δ_one_mkOfSucc]
61+
simp only [len_mk, Fin.coe_castSucc, Fin.coe_eq_castSucc]
62+
arrow_tgt i := by
63+
dsimp [SimplicialObject.δ]
64+
simp only [← FunctorToTypes.map_comp_apply, ← op_comp]
65+
rw [SimplexCategory.δ_zero_mkOfSucc]
66+
67+
lemma spine_map_subinterval {n : ℕ} (j l : ℕ) (hjl : j + l ≤ n) (Δ : X _[n]) :
68+
X.spine l (X.map (subinterval j l (by omega)).op Δ) =
69+
(X.spine n Δ).interval j l (by omega) := by
70+
ext i
71+
· simp only [spine_vertex, Path.interval, ← FunctorToTypes.map_comp_apply, ← op_comp,
72+
const_subinterval_eq]
73+
· simp only [spine_arrow, Path.interval, ← FunctorToTypes.map_comp_apply, ← op_comp,
74+
mkOfSucc_subinterval_eq]
75+
76+
end SSet
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/-
2+
Copyright (c) 2024 Emily Riehl. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Mario Carneiro, Emily Riehl, Joël Riou
5+
-/
6+
import Mathlib.AlgebraicTopology.SimplicialSet.Nerve
7+
import Mathlib.AlgebraicTopology.SimplicialSet.Path
8+
import Mathlib.CategoryTheory.Functor.KanExtension.Adjunction
9+
import Mathlib.CategoryTheory.Functor.KanExtension.Basic
10+
11+
/-!
12+
# Strict Segal simplicial sets
13+
14+
A simplicial set `X` satisfies the `StrictSegal` condition if for all `n`, the map
15+
`X.spine n : X _[n] → X.Path n` is an equivalence, with equivalence inverse
16+
`spineToSimplex {n : ℕ} : Path X n → X _[n]`.
17+
18+
Examples of `StrictSegal` simplicial sets are given by nerves of categories.
19+
20+
TODO: Show that these are the only examples: that a `StrictSegal` simplicial set is isomorphic to
21+
the nerve of its homotopy category.
22+
-/
23+
24+
universe v u
25+
26+
open CategoryTheory
27+
28+
open Simplicial SimplicialObject SimplexCategory
29+
30+
namespace SSet
31+
32+
variable (X : SSet.{u})
33+
34+
/-- A simplicial set `X` satisfies the strict Segal condition if its simplices are uniquely
35+
determined by their spine. -/
36+
class StrictSegal where
37+
/-- The inverse to `X.spine n`.-/
38+
spineToSimplex {n : ℕ} : Path X n → X _[n]
39+
/-- `spineToSimplex` is a right inverse to `X.spine n`.-/
40+
spine_spineToSimplex {n : ℕ} (f : Path X n) : X.spine n (spineToSimplex f) = f
41+
/-- `spineToSimplex` is a left inverse to `X.spine n`.-/
42+
spineToSimplex_spine {n : ℕ} (Δ : X _[n]) : spineToSimplex (X.spine n Δ) = Δ
43+
44+
namespace StrictSegal
45+
variable {X : SSet.{u}} [StrictSegal X] {n : ℕ}
46+
47+
/-- The fields of `StrictSegal` define an equivalence between `X _[n]` and `Path X n`.-/
48+
def spineEquiv (n : ℕ) : X _[n] ≃ Path X n where
49+
toFun := spine X n
50+
invFun := spineToSimplex
51+
left_inv := spineToSimplex_spine
52+
right_inv := spine_spineToSimplex
53+
54+
theorem spineInjective {n : ℕ} : Function.Injective (spineEquiv (X := X) n) := Equiv.injective _
55+
56+
@[simp]
57+
theorem spineToSimplex_vertex (i : Fin (n + 1)) (f : Path X n) :
58+
X.map (const [0] [n] i).op (spineToSimplex f) = f.vertex i := by
59+
rw [← spine_vertex, spine_spineToSimplex]
60+
61+
@[simp]
62+
theorem spineToSimplex_arrow (i : Fin n) (f : Path X n) :
63+
X.map (mkOfSucc i).op (spineToSimplex f) = f.arrow i := by
64+
rw [← spine_arrow, spine_spineToSimplex]
65+
66+
/-- In the presence of the strict Segal condition, a path of length `n` can be "composed" by taking
67+
the diagonal edge of the resulting `n`-simplex. -/
68+
def spineToDiagonal (f : Path X n) : X _[1] := diagonal X (spineToSimplex f)
69+
70+
@[simp]
71+
theorem spineToSimplex_interval (f : Path X n) (j l : ℕ) (hjl : j + l ≤ n) :
72+
X.map (subinterval j l hjl).op (spineToSimplex f) =
73+
spineToSimplex (Path.interval f j l hjl) := by
74+
apply spineInjective
75+
unfold spineEquiv
76+
dsimp
77+
rw [spine_spineToSimplex]
78+
convert spine_map_subinterval X j l hjl (spineToSimplex f)
79+
exact Eq.symm (spine_spineToSimplex f)
80+
81+
theorem spineToSimplex_edge (f : Path X n) (j l : ℕ) (hjl : j + l ≤ n) :
82+
X.map (intervalEdge j l hjl).op (spineToSimplex f) =
83+
spineToDiagonal (Path.interval f j l hjl) := by
84+
unfold spineToDiagonal
85+
rw [← congrArg (diagonal X) (spineToSimplex_interval f j l hjl)]
86+
unfold diagonal
87+
simp only [← FunctorToTypes.map_comp_apply, ← op_comp, diag_subinterval_eq]
88+
89+
end StrictSegal
90+
91+
end SSet
92+
93+
namespace Nerve
94+
95+
open SSet
96+
97+
variable {C : Type*} [Category C] {n : ℕ}
98+
99+
/-- Simplices in the nerve of categories are uniquely determined by their spine. Indeed, this
100+
property describes the essential image of the nerve functor.-/
101+
noncomputable instance strictSegal (C : Type u) [Category.{v} C] : StrictSegal (nerve C) where
102+
spineToSimplex {n} F :=
103+
ComposableArrows.mkOfObjOfMapSucc (fun i ↦ (F.vertex i).obj 0)
104+
(fun i ↦ eqToHom (Functor.congr_obj (F.arrow_src i).symm 0) ≫
105+
(F.arrow i).map' 0 1 ≫ eqToHom (Functor.congr_obj (F.arrow_tgt i) 0))
106+
spine_spineToSimplex {n} F := by
107+
ext i
108+
· exact ComposableArrows.ext₀ rfl
109+
· refine ComposableArrows.ext₁ ?_ ?_ ?_
110+
· exact Functor.congr_obj (F.arrow_src i).symm 0
111+
· exact Functor.congr_obj (F.arrow_tgt i).symm 0
112+
· dsimp
113+
apply ComposableArrows.mkOfObjOfMapSucc_map_succ
114+
spineToSimplex_spine {n} F := by
115+
fapply ComposableArrows.ext
116+
· intro i
117+
rfl
118+
· intro i hi
119+
apply ComposableArrows.mkOfObjOfMapSucc_map_succ
120+
121+
end Nerve

0 commit comments

Comments
 (0)