Skip to content

Commit 4c16d40

Browse files
feat(AlgebraicTopology): inductive construction of StrictSegal structures (#31250)
We obtain a computable `StrictSegal (nerve C)` structure by using an inductive construction based on a new `StrictSegalCore` structure which provides a way to construct a `n + 1`-simplex by from a `1`-simplex and a `n`-simplex satisfying a compatibility. Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent c878df9 commit 4c16d40

File tree

4 files changed

+177
-29
lines changed

4 files changed

+177
-29
lines changed

Mathlib/AlgebraicTopology/SimplicialSet/Coskeletal.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ instance (C : Type u) [Category.{v} C] :
243243
recorded by the composite functor `nerveFunctor₂`. -/
244244
def nerveFunctor₂ : Cat.{v, u} ⥤ SSet.Truncated 2 := nerveFunctor ⋙ truncation 2
245245

246+
instance (X : Cat.{v, u}) : (nerveFunctor₂.obj X).IsStrictSegal := by
247+
dsimp [nerveFunctor₂]
248+
infer_instance
249+
246250
/-- The natural isomorphism between `nerveFunctor` and `nerveFunctor₂ ⋙ Truncated.cosk 2` whose
247251
components `nerve C ≅ (Truncated.cosk 2).obj (nerveFunctor₂.obj C)` shows that nerves of categories
248252
are 2-coskeletal. -/

Mathlib/AlgebraicTopology/SimplicialSet/Path.lean

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,20 @@ abbrev vertex (f : Path X n) (i : Fin (n + 1)) : X _⦋0⦌ :=
198198
abbrev arrow (f : Path X n) (i : Fin n) : X _⦋1⦌ :=
199199
Truncated.Path.arrow f i
200200

201+
lemma congr_vertex {f g : Path X n} (h : f = g) (i : Fin (n + 1)) :
202+
f.vertex i = g.vertex i := by rw [h]
203+
204+
lemma congr_arrow {f g : Path X n} (h : f = g) (i : Fin n) :
205+
f.arrow i = g.arrow i := by rw [h]
206+
201207
/-- The source of a 1-simplex in a path is identified with the source vertex. -/
202208
lemma arrow_src (f : Path X n) (i : Fin n) :
203-
X.map (δ 1).op (f.arrow i) = f.vertex i.castSucc :=
209+
X.δ 1 (f.arrow i) = f.vertex i.castSucc :=
204210
Truncated.Path.arrow_src f i
205211

206212
/-- The target of a 1-simplex in a path is identified with the target vertex. -/
207213
lemma arrow_tgt (f : Path X n) (i : Fin n) :
208-
X.map (δ 0).op (f.arrow i) = f.vertex i.succ :=
214+
X.δ 0 (f.arrow i) = f.vertex i.succ :=
209215
Truncated.Path.arrow_tgt f i
210216

211217
@[ext]
@@ -218,11 +224,23 @@ lemma ext {f g : Path X n} (hᵥ : f.vertex = g.vertex) (hₐ : f.arrow = g.arro
218224
lemma ext' {f g : Path X (n + 1)} (h : ∀ i, f.arrow i = g.arrow i) : f = g :=
219225
Truncated.Path.ext' h
220226

227+
@[ext]
228+
lemma ext₀ {f g : Path X 0} (h : f.vertex 0 = g.vertex 0) : f = g := by
229+
ext i
230+
· fin_cases i; exact h
231+
· fin_cases i
232+
221233
/-- For `j + l ≤ n`, a path of length `n` restricts to a path of length `l`, namely
222234
the subpath spanned by the vertices `j ≤ i ≤ j + l` and edges `j ≤ i < j + l`. -/
223-
def interval (f : Path X n) (j l : ℕ) (h : j + l ≤ n := by omega) : Path X l :=
235+
def interval (f : Path X n) (j l : ℕ) (h : j + l ≤ n := by grind) : Path X l :=
224236
Truncated.Path.interval f j l h
225237

238+
lemma arrow_interval (f : Path X n) (j l : ℕ) (k' : Fin l) (k : Fin n)
239+
(h : j + l ≤ n := by omega) (hkk' : j + k' = k := by grind) :
240+
(f.interval j l h).arrow k' = f.arrow k := by
241+
dsimp [interval, arrow, Truncated.Path.interval, Truncated.Path.arrow]
242+
congr
243+
226244
variable {X Y : SSet.{u}} {n : ℕ}
227245

228246
/-- Maps of simplicial sets induce maps of paths in a simplicial set. -/
@@ -265,6 +283,20 @@ lemma spine_arrow (Δ : X _⦋n⦌) (i : Fin n) :
265283
(X.spine n Δ).arrow i = X.map (mkOfSucc i).op Δ :=
266284
rfl
267285

286+
lemma spine_δ₀ {m : ℕ} (x : X _⦋m + 1⦌) :
287+
X.spine m (X.δ 0 x) = (X.spine (m + 1) x).interval 1 m := by
288+
obtain _ | m := m
289+
· ext
290+
simp [spine, Path.vertex, Truncated.Path.vertex, SimplicialObject.truncation,
291+
Truncated.spine, Path.interval, Truncated.Path.interval, Truncated.inclusion,
292+
Truncated.Hom.tr, ← SimplexCategory.δ_zero_eq_const, ← SimplicialObject.δ_def]
293+
· ext i
294+
dsimp
295+
rw [SimplicialObject.δ_def, ← FunctorToTypes.map_comp_apply, ← op_comp,
296+
SimplexCategory.mkOfSucc_δ_gt (j := 0) (i := i) (by simp)]
297+
symm
298+
exact Path.arrow_interval _ _ _ _ _ _ (by rw [Fin.val_succ, add_comm])
299+
268300
/-- For `m ≤ n + 1`, the `m`-spine of `X` factors through the `n + 1`-truncation
269301
of `X`. -/
270302
lemma truncation_spine (m : ℕ) (h : m ≤ n + 1) :

Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean

Lines changed: 129 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,53 @@ structure StrictSegal where
4848

4949
/-- For an `n + 1`-truncated simplicial set `X`, `IsStrictSegal X` asserts the
5050
mere existence of an inverse to `spine X m` for all `m ≤ n + 1`. -/
51-
class IsStrictSegal : Prop where
52-
segal (m : ℕ) (h : m ≤ n + 1 := by omega) : Function.Bijective (X.spine m)
51+
class IsStrictSegal (X : SSet.Truncated.{u} (n + 1)) : Prop where
52+
spine_bijective (X) (m : ℕ) (h : m ≤ n + 1 := by grind) : Function.Bijective (X.spine m)
53+
54+
export IsStrictSegal (spine_bijective)
55+
56+
@[deprecated (since := "2025-11-04")] alias IsStrictSegal.segal := spine_bijective
57+
58+
lemma spine_injective (X : SSet.Truncated.{u} (n + 1)) [X.IsStrictSegal]
59+
{m : ℕ} {h : m ≤ n + 1} :
60+
Function.Injective (X.spine m) :=
61+
(spine_bijective X m).injective
62+
63+
lemma spine_surjective (X : SSet.Truncated.{u} (n + 1)) [X.IsStrictSegal]
64+
{m : ℕ} (p : X.Path m) (h : m ≤ n + 1 := by grind) :
65+
∃ (x : X _⦋m⦌ₙ₊₁), X.spine m _ x = p :=
66+
(spine_bijective X m).surjective p
67+
68+
variable {X} in
69+
lemma IsStrictSegal.ext [X.IsStrictSegal] {d : ℕ} {hd} {x y : X _⦋d + 1⦌ₙ₊₁}
70+
(h : ∀ (i : Fin (d + 1)),
71+
X.map (SimplexCategory.Truncated.Hom.tr (mkOfSucc i)).op x =
72+
X.map (SimplexCategory.Truncated.Hom.tr (mkOfSucc i)).op y) :
73+
x = y :=
74+
X.spine_injective (by ext i; apply h)
75+
76+
variable {X} in
77+
lemma IsStrictSegal.hom_ext {Y : SSet.Truncated.{u} (n + 1)} [Y.IsStrictSegal]
78+
{f g : X ⟶ Y} (h : ∀ (x : X _⦋1⦌ₙ₊₁), f.app _ x = g.app _ x) : f = g := by
79+
ext ⟨⟨m, hm⟩⟩ x
80+
induction m using SimplexCategory.rec with | _ m
81+
obtain _ | m := m
82+
· have fac := δ_comp_σ_self (i := (0 : Fin 1))
83+
dsimp at fac
84+
simpa [← FunctorToTypes.naturality,
85+
← FunctorToTypes.map_comp_apply, ← op_comp,
86+
← SimplexCategory.Truncated.Hom.tr_comp, fac] using
87+
congr_arg (Y.map (SimplexCategory.Truncated.Hom.tr (SimplexCategory.δ 0)).op)
88+
(h (X.map (SimplexCategory.Truncated.Hom.tr (SimplexCategory.σ 0)).op x))
89+
· exact IsStrictSegal.ext (fun i ↦ by simp only [← FunctorToTypes.naturality, h])
5390

5491
namespace StrictSegal
5592

5693
/-- Given `IsStrictSegal X`, a choice of inverse to `spine X m` for all
5794
`m ≤ n + 1` determines an inhabitant of `StrictSegal X`. -/
5895
noncomputable def ofIsStrictSegal [IsStrictSegal X] : StrictSegal X where
5996
spineToSimplex m h :=
60-
Equiv.ofBijective (X.spine m) (IsStrictSegal.segal m h) |>.invFun
97+
Equiv.ofBijective (X.spine m) (X.spine_bijective m h) |>.invFun
6198
spine_spineToSimplex m _ :=
6299
funext <| Equiv.ofBijective (X.spine m) _ |>.right_inv
63100
spineToSimplex_spine m _ :=
@@ -102,7 +139,7 @@ end autoParam
102139
/-- The unique existence of an inverse to `spine X m` for all `m ≤ n + 1`
103140
implies the mere existence of such an inverse. -/
104141
lemma isStrictSegal (sx : StrictSegal X) : IsStrictSegal X where
105-
segal m h := sx.spineEquiv m h |>.bijective
142+
spine_bijective m h := sx.spineEquiv m h |>.bijective
106143

107144
variable (m : ℕ) (h : m ≤ n + 1)
108145

@@ -245,11 +282,15 @@ variable {X} (sx : StrictSegal X)
245282

246283
/-- A `StrictSegal` structure on a simplicial set `X` restricts to a
247284
`Truncated.StrictSegal` structure on the `n + 1`-truncation of `X`. -/
248-
def truncation (n : ℕ) : truncation (n + 1) |>.obj X |>.StrictSegal where
285+
protected def truncation (n : ℕ) : truncation (n + 1) |>.obj X |>.StrictSegal where
249286
spineToSimplex _ _ := sx.spineToSimplex
250287
spine_spineToSimplex m _ := sx.spine_spineToSimplex m
251288
spineToSimplex_spine m _ := sx.spineToSimplex_spine m
252289

290+
instance [X.IsStrictSegal] (n : ℕ) :
291+
((truncation (n + 1)).obj X).IsStrictSegal :=
292+
((ofIsStrictSegal X).truncation n).isStrictSegal
293+
253294
@[simp]
254295
lemma spine_spineToSimplex_apply {n : ℕ} (f : Path X n) :
255296
X.spine n (sx.spineToSimplex f) = f :=
@@ -386,6 +427,79 @@ lemma spine_δ_arrow_eq (h : j = i.succ.castSucc) :
386427
rw [mkOfSucc_δ_eq h, spineToSimplex_edge]
387428

388429
end StrictSegal
430+
431+
/-- Helper structure in order to show that a simplicial set is strict Segal. -/
432+
structure StrictSegalCore (n : ℕ) where
433+
/-- Map which produces a `n + 1`-simplex from a `1`-simplex and a `n`-simplex when
434+
the target vertex of the `1`-simplex equals the zeroth simplex of the `n`-simplex. -/
435+
concat (x : X _⦋1⦌) (s : X _⦋n⦌) (h : X.δ 0 x = X.map (SimplexCategory.const _ _ 0).op s) :
436+
X _⦋n + 1
437+
map_mkOfSucc_zero_concat x s h : X.map (mkOfSucc 0).op (concat x s h) = x
438+
δ₀_concat x s h : X.δ 0 (concat x s h) = s
439+
injective {x y : X _⦋n + 1⦌} (h : X.map (mkOfSucc 0).op x = X.map (mkOfSucc 0).op y)
440+
(h₀ : X.δ 0 x = X.δ 0 y) : x = y
441+
442+
namespace StrictSegalCore
443+
444+
variable {X} (h : ∀ n, X.StrictSegalCore n) {n : ℕ} (p : X.Path n)
445+
446+
/-- Auxiliary definition for `StrictSegalCore.spineToSimplex`. -/
447+
def spineToSimplexAux : { s : X _⦋n⦌ // X.spine _ s = p } := by
448+
induction n with
449+
| zero => exact ⟨p.vertex 0, by aesop⟩
450+
| succ n hn =>
451+
refine ⟨(h n).concat (p.arrow 0) (hn (p.interval 1 n)).val ?_, ?_⟩
452+
· rw [p.arrow_tgt 0]
453+
exact Path.congr_vertex (hn (p.interval 1 n)).prop.symm 0
454+
· ext i
455+
obtain rfl | ⟨i, rfl⟩ := i.eq_zero_or_eq_succ
456+
· dsimp
457+
rw [map_mkOfSucc_zero_concat]
458+
· simpa [spine_arrow, ← SimplexCategory.mkOfSucc_δ_gt (j := 0) (i := i) (by simp),
459+
op_comp, FunctorToTypes.map_comp_apply, ← SimplicialObject.δ_def, δ₀_concat,
460+
← p.arrow_interval 1 n i i.succ (by grind) (by grind [Fin.val_succ])] using
461+
Path.congr_arrow (hn (p.interval 1 n)).prop i
462+
463+
/-- Auxiliary definition for `StrictSegal.ofCore`. -/
464+
def spineToSimplex : X _⦋n⦌ := (spineToSimplexAux h p).val
465+
466+
@[simp]
467+
lemma spine_spineToSimplex : X.spine n (spineToSimplex h p) = p := (spineToSimplexAux h p).prop
468+
469+
lemma spineToSimplex_zero (p : X.Path 0) : spineToSimplex h p = p.vertex 0 := rfl
470+
471+
lemma spineToSimplex_succ (p : X.Path (n + 1)) :
472+
spineToSimplex h p = (h n).concat (p.arrow 0) (spineToSimplex h (p.interval 1 n)) (by
473+
rw [p.arrow_tgt 0]
474+
exact Path.congr_vertex (spine_spineToSimplex h (p.interval 1 n)).symm 0) :=
475+
rfl
476+
477+
lemma map_mkOfSucc_zero_spineToSimplex (p : X.Path (n + 1)) :
478+
X.map (mkOfSucc 0).op (spineToSimplex h p) = p.arrow 0 := by
479+
rw [spineToSimplex_succ, map_mkOfSucc_zero_concat]
480+
481+
lemma δ₀_spineToSimplex (p : X.Path (n + 1)) :
482+
X.δ 0 (spineToSimplex h p) = spineToSimplex h (p.interval 1 n) := by
483+
rw [spineToSimplex_succ, δ₀_concat]
484+
485+
@[simp]
486+
lemma spineToSimplex_spine (s : X _⦋n⦌) : spineToSimplex h (X.spine _ s) = s := by
487+
induction n with
488+
| zero => simp [spineToSimplex_zero]
489+
| succ n hn =>
490+
exact (h n).injective (map_mkOfSucc_zero_spineToSimplex _ _)
491+
(by rw [δ₀_spineToSimplex, ← hn (X.δ 0 s), spine_δ₀])
492+
493+
end StrictSegalCore
494+
495+
variable {X} in
496+
/-- Given a simplicial set `X`, this constructs a `StrictSegal` structure for `X` from
497+
`StrictSegalCore` structures for all `n : ℕ`. -/
498+
def StrictSegal.ofCore (h : ∀ n, X.StrictSegalCore n) : X.StrictSegal where
499+
spineToSimplex := StrictSegalCore.spineToSimplex h
500+
spine_spineToSimplex := by aesop
501+
spineToSimplex_spine n := by aesop
502+
389503
end SSet
390504

391505
namespace CategoryTheory.Nerve
@@ -396,27 +510,16 @@ variable (C : Type u) [Category.{v} C]
396510

397511
/-- Simplices in the nerve of categories are uniquely determined by their spine.
398512
Indeed, this property describes the essential image of the nerve functor. -/
399-
noncomputable def strictSegal : StrictSegal (nerve C) where
400-
spineToSimplex {n} F :=
401-
ComposableArrows.mkOfObjOfMapSucc (fun i ↦ (F.vertex i).obj 0)
402-
(fun i ↦ eqToHom (Functor.congr_obj (F.arrow_src i).symm 0) ≫
403-
(F.arrow i).map' 0 1 ≫ eqToHom (Functor.congr_obj (F.arrow_tgt i) 0))
404-
spine_spineToSimplex n := by
405-
ext F i
406-
· exact ComposableArrows.ext₀ rfl
407-
· refine ComposableArrows.ext₁ ?_ ?_ ?_
408-
· exact Functor.congr_obj (F.arrow_src i).symm 0
409-
· exact Functor.congr_obj (F.arrow_tgt i).symm 0
410-
· dsimp
411-
apply ComposableArrows.mkOfObjOfMapSucc_map_succ
412-
spineToSimplex_spine n := by
413-
ext F
414-
fapply ComposableArrows.ext
415-
· intro i
416-
rfl
417-
· intro i hi
418-
dsimp
419-
exact ComposableArrows.mkOfObjOfMapSucc_map_succ _ _ i hi
513+
def strictSegal : StrictSegal (nerve C) :=
514+
StrictSegal.ofCore (fun n ↦
515+
{ concat f s h := s.precomp (f.hom ≫ eqToHom (Functor.congr_obj h 0))
516+
map_mkOfSucc_zero_concat f s h :=
517+
ComposableArrows.ext₁ rfl (Functor.congr_obj h 0).symm (by cat_disch)
518+
δ₀_concat f s h := rfl
519+
injective {f g} h h₀ :=
520+
ComposableArrows.ext_succ (Functor.congr_obj h 0) h₀
521+
((Arrow.mk_eq_mk_iff _ _).1
522+
(DFunLike.congr_arg ComposableArrows.arrowEquiv h)).2.2 })
420523

421524
instance isStrictSegal : IsStrictSegal (nerve C) :=
422525
strictSegal C |>.isStrictSegal

Mathlib/CategoryTheory/ComposableArrows/Basic.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authors: Joël Riou
55
-/
66
import Mathlib.Algebra.Group.Nat.Defs
77
import Mathlib.CategoryTheory.Category.Preorder
8+
import Mathlib.CategoryTheory.Comma.Arrow
89
import Mathlib.CategoryTheory.EpiMono
910
import Mathlib.Data.Fintype.Basic
1011
import Mathlib.Tactic.FinCases
@@ -275,6 +276,14 @@ lemma ext₁ {F G : ComposableArrows C 1}
275276
lemma mk₁_surjective (X : ComposableArrows C 1) : ∃ (X₀ X₁ : C) (f : X₀ ⟶ X₁), X = mk₁ f :=
276277
⟨_, _, X.map' 0 1, ext₁ rfl rfl (by simp)⟩
277278

279+
/-- The bijection between `ComposableArrows C 1` and `Arrow C`. -/
280+
@[simps]
281+
def arrowEquiv : ComposableArrows C 1 ≃ Arrow C where
282+
toFun F := Arrow.mk F.hom
283+
invFun f := mk₁ f.hom
284+
left_inv F := ComposableArrows.ext₁ rfl rfl (by simp)
285+
right_inv _ := rfl
286+
278287
variable (F)
279288

280289
namespace Precomp

0 commit comments

Comments
 (0)