Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Require Import Modalities.Modality.Require Import Truncations.Core Truncations.SeparatedTrunc.Require Import Algebra.AbGroups.Require Import WildCat.LocalOpen Scope nat_scope.LocalOpen Scope pointed_scope.LocalOpen Scope path_scope.(** The type that the nth homotopy group will have. *)DefinitionHomotopyGroup_type (n : nat) : Type
:= match n with
| 0 => pType
| n.+1 => Group
end.(** Every homotopy group is, in particular, a pointed type. *)DefinitionHomotopyGroup_type_ptype (n : nat) : HomotopyGroup_type n -> pType
:= match n return HomotopyGroup_type n -> pType with
| 0 => funX => X
(* This works because [ptype_group] is already a coercion. *)
| n.+1 => funG => G
end.CoercionHomotopyGroup_type_ptype : HomotopyGroup_type >-> pType.(** We construct the wildcat structure on [HomotopyGroup_type] in the obvious way. *)Instanceisgraph_homotopygroup_type (n : nat)
: IsGraph (HomotopyGroup_type n) := ltac:(destruct n; exact _).Instanceis2graph_homotopygroup_type (n : nat)
: Is2Graph (HomotopyGroup_type n) := ltac:(destruct n; exact _).Instanceis01cat_homotopygroup_type (n : nat)
: Is01Cat (HomotopyGroup_type n) := ltac:(destruct n; exact _).Instanceis1cat_homotopygroup_type (n : nat)
: Is1Cat (HomotopyGroup_type n) := ltac:(destruct n; exact _).Instanceis0functor_homotopygroup_type_ptype (n : nat)
: Is0Functor (HomotopyGroup_type_ptype n)
:= ltac:(destruct n; exact _).Instanceis1functor_homotopygroup_type_ptype (n : nat)
: Is1Functor (HomotopyGroup_type_ptype n)
:= ltac:(destruct n; exact _).(** We first define [Pi 1 X], and use this to define [Pi n X]. The reason is to make it easier for Coq to see that [Pi (n.+1) X] is definitionally equal to [Pi 1 (iterated_loops n X)] *)
apply concat_pV.Defined.(** Definition of the nth homotopy group *)
n: nat X: pType
HomotopyGroup_type n
n: nat X: pType
HomotopyGroup_type n
X: pType
HomotopyGroup_type 0
n: nat X: pType
HomotopyGroup_type n.+1
n: nat X: pType
HomotopyGroup_type n.+1
exact (Pi1 (iterated_loops n X)).Defined.(** See [pi_loops] below for an alternate unfolding. *)Definitionpi_succnX : Pi n.+1 X $<~> Pi 1 (iterated_loops n X)
:= grp_iso_id.ModulePiUtf8.Notation"'π'" := Pi.EndPiUtf8.Instanceishset_pi {n : nat} {X : pType}
: IsHSet (Pi n X)
:= ltac:(destruct n; exact _).(** When n >= 2 we have that the nth homotopy group is an abelian group. Note that we don't actually define it as an abelian group but merely show that it is one. This would cause lots of complications with the typechecker. *)
n: nat X: pType
Commutative sg_op
n: nat X: pType
Commutative sg_op
n: nat X: pType x, y: Pi n.+2 X
sg_op x y = sg_op y x
n: nat X: pType y, x: loops (iterated_loops n.+1 X)
sg_op (tr x) (tr y) = sg_op (tr y) (tr x)
n: nat X: pType y, x: loops (iterated_loops n.+1 X)
x @ y = y @ x
apply eckmann_hilton.Defined.(** For the same reason as above, we make [Pi1] a functor before making [Pi] a functor. *)
(** The conditions for [Pi1] to be a 1-functor only involve equalities of maps between groups, which reduce to equalities of maps between types. Type inference shows that [Tr 0 o loops] is a 1-functor, and so it follows that [Pi1] is a 1-functor. *)
apply Build_Is1Functor; intros;
[ by rapply (fmap2 _ (is1functor_F := is1f))
| by rapply (fmap_id _ (is1functor_F := is1f))
| by rapply (fmap_comp _ (is1functor_F := is1f)) ].Defined.Instanceis1functor_pi (n : nat) : Is1Functor (Pi n)
:= ltac:(destruct n; exact _).(** Sometimes it is convenient to regard [Pi n] as landing in pointed types. On objects, this is handled by the coercion [HomotopyGroup_type_ptype], but on morphisms it doesn't seem possible to define a coercion. So we explicitly name the composite functor. *)DefinitionpPi (n : nat) : pType -> pType := HomotopyGroup_type_ptype n o Pi n.Instanceis0functor_ppi (n : nat) : Is0Functor (pPi n) := _.Instanceis1functor_ppi (n : nat) : Is1Functor (pPi n) := _.(** [pPi] is equal to a more explicit map. These are definitional for [n = 0] and [n] a successor; it would be nice to make them definitional for generic [n]. *)Definitionppi_ptr_iterated_loops (n : nat)
: pPi n = pTr 0 o iterated_loops n
:= ltac:(destruct n; reflexivity).(** Here is the associated object-wise equivalence, which is the identity map for [0] and successors. *)Definitionpequiv_ppi_ptr_iterated_loops (n : nat) (X : pType)
: pPi n X <~>* pTr 0 (iterated_loops n X)
:= ltac:(destruct n; exact pequiv_pmap_idmap).(** These equivalences are natural. Put another way, we can compute [fmap Pi] in terms of the composite functor, up to the equivalences above. For [n = 0] or [n] a successor, we can omit the equivalences; for [n = 0], the induced maps are definitionally equal as pointed maps; for [n] a successfor the underlying unpointed maps are definitionally equal, but the pointedness proofs are not, and this is handled by [phomotopy_homotopy_hset]. *)
n: nat X, Y: pType f: X ->* Y
pequiv_ppi_ptr_iterated_loops n Y o* fmap (pPi n) f ==*
fmap (pTr 0) (fmap (iterated_loops n) f)
o* pequiv_ppi_ptr_iterated_loops n X
n: nat X, Y: pType f: X ->* Y
pequiv_ppi_ptr_iterated_loops n Y o* fmap (pPi n) f ==*
fmap (pTr 0) (fmap (iterated_loops n) f)
o* pequiv_ppi_ptr_iterated_loops n X
srapply phomotopy_homotopy_hset; reflexivity.Defined.(** [Pi n.+1] sends equivalences to group isomorphisms. *)Definitiongroupiso_pi_functor (n : nat) {XY : pType} (e : X <~>* Y)
: Pi n.+1 X $<~> Pi n.+1 Y
:= emap (Pi n.+1) e.(** The homotopy groups of a loop space are those of the space shifted. *)
n: nat X: pType
Pi n.+1 X <~>* Pi n (loops X)
n: nat X: pType
Pi n.+1 X <~>* Pi n (loops X)
X: pType
Pi 1 X <~>* Pi 0 (loops X)
n: nat X: pType
Pi n.+2 X <~>* Pi n.+1 (loops X)
n: nat X: pType
Pi n.+2 X <~>* Pi n.+1 (loops X)
n: nat X: pType
iterated_loops n.+1 X $<~> iterated_loops n (loops X)
apply unfold_iterated_loops'.Defined.(** Except in the lowest case, this can be expressed as an isomorphism of groups. *)
n: nat X: pType
Pi n.+2 X $<~> Pi n.+1 (loops X)
n: nat X: pType
Pi n.+2 X $<~> Pi n.+1 (loops X)
n: nat X: pType
[pt = pt, 1] <~>* iterated_loops n (loops X)
apply unfold_iterated_loops'.Defined.(** Naturality of [pi_loops]. *)
n: nat X, Y: pType f: X ->* Y
pi_loops n Y o* fmap (Pi n.+1) f ==*
fmap (pPi n o loops) f o* pi_loops n X
n: nat X, Y: pType f: X ->* Y
pi_loops n Y o* fmap (Pi n.+1) f ==*
fmap (pPi n o loops) f o* pi_loops n X
X, Y: pType f: X ->* Y x: Pi 1 X
(pi_loops 0 Y o* fmap (Pi 1) f) x =
(fmap (pPi 0 o loops) f o* pi_loops 0 X) x
n: nat X, Y: pType f: X ->* Y x: Pi n.+2 X
(pi_loops n.+1 Y o* fmap (Pi n.+2) f) x =
(fmap (pPi n.+1 o loops) f o* pi_loops n.+1 X) x
n: nat X, Y: pType f: X ->* Y x: Pi n.+2 X
(pi_loops n.+1 Y o* fmap (Pi n.+2) f) x =
(fmap (pPi n.+1 o loops) f o* pi_loops n.+1 X) x
exact (pointed_htpy (unfold_iterated_fmap_loops n.+1 f)).Defined.(** Homotopy groups preserve products. This is a direct proof, but below we give a second proof whose underlying map is the natural one. *)
n: nat X, Y: pType
pPi n (X * Y) <~>* pPi n X * pPi n Y
n: nat X, Y: pType
pPi n (X * Y) <~>* pPi n X * pPi n Y
(* First we re-express this in terms of the composite [pTr 0 o iterated_loops n]. *)
n: nat X, Y: pType
pTr 0 (iterated_loops n (X * Y)) <~>*
pPi n X * pPi n Y
n: nat X, Y: pType
pTr 0 (iterated_loops n (X * Y)) <~>*
pTr 0 (iterated_loops n X) *
pTr 0 (iterated_loops n Y)
(* For this composite, the proof is straightforward. *)
n: nat X, Y: pType
iterated_loops n (X * Y) <~>* ?Goal
n: nat X, Y: pType
pTr 0?Goal <~>*
pTr 0 (iterated_loops n X) *
pTr 0 (iterated_loops n Y)
n: nat X, Y: pType
pTr 0 (iterated_loops n X * iterated_loops n Y) <~>*
pTr 0 (iterated_loops n X) *
pTr 0 (iterated_loops n Y)
n: nat X, Y: pType
Trunc 0 (iterated_loops n X * iterated_loops n Y) <~>
Trunc 0 (iterated_loops n X) *
Trunc 0 (iterated_loops n Y)
n: nat X, Y: pType
?Goal (tr ispointed_prod) = ispointed_prod
n: nat X, Y: pType
Trunc 0 (iterated_loops n X * iterated_loops n Y) <~>
Trunc 0 (iterated_loops n X) *
Trunc 0 (iterated_loops n Y)
exact (equiv_O_prod_cmp 0 _ _).
n: nat X, Y: pType
equiv_O_prod_cmp (Tr 0%nat) (iterated_loops n X)
(iterated_loops n Y) (tr ispointed_prod) =
ispointed_prod
reflexivity.Defined.(** The pointed map from left-to-right below, coming from functoriality, is an equivalence. *)
n: nat X, Y: pType
pPi n (X * Y) <~>* pPi n X * pPi n Y
n: nat X, Y: pType
pPi n (X * Y) <~>* pPi n X * pPi n Y
n: nat X, Y: pType
pPi n (X * Y) ->* pPi n X * pPi n Y
n: nat X, Y: pType
IsEquiv ?pointed_equiv_fun
(* This describes the natural map. *)
n: nat X, Y: pType
pPi n (X * Y) ->* pPi n X * pPi n Y
n: nat X, Y: pType
pPi n (X * Y) ->* pPi n X
n: nat X, Y: pType
pPi n (X * Y) ->* pPi n Y
n: nat X, Y: pType
pPi n (X * Y) ->* pPi n X
exact (fmap (pPi n) (@pfst X Y)).
n: nat X, Y: pType
pPi n (X * Y) ->* pPi n Y
exact (fmap (pPi n) (@psnd X Y)).(* To see that it is an equivalence, we show that it is homotopic to [pi_prod']. *)
n: nat X, Y: pType
IsEquiv
(equiv_pprod_coind (pfam_const (pPi n X))
(pfam_const (pPi n Y))
(fmap (pPi n) pfst, fmap (pPi n) psnd))
n: nat X, Y: pType
pi_prod' X Y ==
equiv_pprod_coind (pfam_const (pPi n X))
(pfam_const (pPi n Y))
(fmap (pPi n) pfst, fmap (pPi n) psnd)
n: nat X, Y: pType xy: pPi n (X * Y)
pi_prod' X Y xy =
equiv_pprod_coind (pfam_const (pPi n X))
(pfam_const (pPi n Y))
(fmap (pPi n) pfst, fmap (pPi n) psnd) xy
exact (equiv_isequiv (pi_prod X Y (n:=n.+1))).Defined.(** Homotopy groups of truncations *)(** An [n]-connected map induces an equivalence on the nth homotopy group. We first state this for [pTr 0 o iterated_loops n], since the proof works for general [n], and then we deduce the result for [pPi n] afterwards. *)
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
IsConnMap (Tr 0) (fmap (iterated_loops n) f)
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
IsConnMap (Tr (trunc_index_inc' 0 n)) f
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
IsConnMap (Tr (trunc_index_inc' (-2) n).+2) f
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
IsConnMap (Tr (trunc_index_inc (-2) n).+2) f
assumption.Defined.(** The same holds for [pPi n]. *)
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
IsEquiv (fmap (pPi n) f)
H: Univalence n: nat X, Y: pType f: X ->* Y IsConnMap0: IsConnMap (Tr n) f
IsEquiv (fmap (pPi n) f)
(* For [n = 0] and [n] a successor, [fmap (pPi n) f] is definitionally equal to the map in the previous result as a map of types. *)destruct n; tapply isequiv_pi_connmap'.Defined.Definitionpequiv_pi_connmap `{Univalence} (n : nat) {X Y : pType} (f : X ->* Y)
`{!IsConnMap n f}
: Pi n X <~>* Pi n Y
:= Build_pEquiv (fmap (pPi n) f) _.(** For positive [n], it is a group isomorphism. *)Definitiongrp_iso_pi_connmap `{Univalence} (n : nat) {X Y : pType} (f : X ->* Y)
`{!IsConnMap n.+1 f}
: GroupIsomorphism (Pi n.+1 X) (Pi n.+1 Y)
:= Build_GroupIsomorphism _ _ (fmap (Pi n.+1) f) (isequiv_pi_connmap n.+1 f).(** As a consequence, the truncation map [ptr : X -> pTr n X] induces an equivalence on [Pi n]. We don't make this an instance, since it is found by typeclass search. *)Definitionisequiv_pi_Tr `{Univalence} (n : nat) (X : pType)
: IsEquiv (fmap (pPi n) ptr : Pi n X -> Pi n (pTr n X))
:= _.Definitionpequiv_pi_Tr `{Univalence} (n : nat) (X : pType)
: Pi n X <~>* Pi n (pTr n X)
:= Build_pEquiv (fmap (pPi n) ptr) _.(** For positive [n], it is a group isomorphism. *)Definitiongrp_iso_pi_Tr `{Univalence} (n : nat) (X : pType)
: GroupIsomorphism (Pi n.+1 X) (Pi n.+1 (pTr n.+1 X))
:= grp_iso_pi_connmap n ptr.(** An [n]-connected map induces a surjection on [n+1]-fold loop spaces and [Pi (n+1)]. *)
H: Univalence n: nat X, Y: pType f: X ->* Y C: IsConnMap (Tr n) f