{- | The generalized Blakers-Massey theorem. - The proof combines ideas from the following papers: - * Kuen-Bang Hou (Favonia), Eric Finster, Dan Licata, Peter LeFanu Lumsdaine, A mechanization of the Blakers-Massey connectivity theorem in Homotopy Type Theory (https://arxiv.org/abs/1605.03227, https://github.com/HoTT/HoTT-Agda/blob/master/theorems/homotopy/BlakersMassey.agda) - * Mathieu Anel, Georg Biedermann, Eric Finster, André Joyal, A Generalized Blakers-Massey Theorem (https://arxiv.org/abs/1703.09050) - -} \import Equiv \import Equiv.Sigma \import Equiv.Univalence \import HLevel \import Homotopy.Fibration \import Homotopy.Join \import Homotopy.Localization.Connected \import Homotopy.Localization.Universe \import Homotopy.Pushout \import Logic \import Paths \import Paths.Meta \lemma genBlakersMassey {d : Data} (x0 : X) (y0 : Y) : isConnectedMap (pbMap {d} {x0} {y0}) => \lam p => surjective (POData.pullback_pushout-surjective {\new POData Y X (\lam y x => Q x y)} y0 x0 (inv (pmap swap p))) p \where { \open Localization -- | It is easier to prove the theorem if the type ``\Sigma (y : Y) (Q x0 y)`` is inhabited. \lemma surjective {d : Data} {x0 : X} {y0 : Y} (q : TruncP (\Sigma (y : Y) (Q x0 y))) : isConnectedMap (pbMap {d} {x0} {y0}) \elim q | inP (y,q0) => \lam p => contr=>isConnected (Fib pbMap p) (DataExt.code-contr {\new DataExt { | Data => d | x0 => x0 | y0 => y | q0 => q0 }} p) \class EquivData \noclassifying (A B : \hType) \extends ReflUniverse { | M : A -> Connected | N : B -> Connected | f : \Sigma (a : A) (M a) -> \Sigma (b : B) (N b) | g : \Sigma (b : B) (N b) -> \Sigma (a : A) (M a) | p : \Pi (a : A) (m : M a) -> (g (f (a,m))).1 = a | q : \Pi (b : B) (n : N b) -> (f (g (b,n))).1 = b \func eval (a : A) (m : M a) : lift (\lam a => sec {Connected.equiv {M a} (LType B)} (\lam m => lEta (f (a,m)).1)) (lEta a) = lEta (f (a,m)).1 => lift-prop (\lam a => sec {Connected.equiv {M a} (LType B)} (\lam m => lEta (f (a,m)).1)) a *> path (\lam i => (f_sec {Connected.equiv {M a} (LType B)} (\lam m => lEta (f (a,m)).1) @ i) m) \lemma equiv-lemma : Equiv {LType A} {LType B} (lift (\lam a => sec {Connected.equiv {M a} (LType B)} (\lam m => lEta (f (a,m)).1))) => \let | E1 a => Connected.equiv {M a} (LType B) | E2 b => Connected.equiv {N b} (LType A) | f1 a m => lEta (f (a,m)).1 | g1 b n => lEta (g (b,n)).1 | F a => sec {E1 a} (f1 a) | G b => sec {E2 b} (g1 b) \in localization-equiv F G (\lam a => sec {Connected.equiv {M a} (pathLocal (lift G (F a)) (lEta a))} (\lam m => lift G (F a) ==< path (\lam i => lift G ((f_sec {E1 a} (f1 a) @ i) m)) >== lift G (f1 a m) ==< lift-prop G (f (a,m)).1 >== G (f (a,m)).1 ==< path (\lam i => (f_sec {E2 (f (a,m)).1} (g1 (f (a,m)).1) @ i) (f (a,m)).2) >== inL (g (f (a,m))).1 ==< pmap inL (p a m) >== inL a `qed)) (\lam b => sec {Connected.equiv {N b} (pathLocal (lift F (G b)) (lEta b))} (\lam n => lift F (G b) ==< path (\lam i => lift F ((f_sec {E2 b} (g1 b) @ i) n)) >== lift F (g1 b n) ==< lift-prop F (g (b,n)).1 >== F (g (b,n)).1 ==< path (\lam i => (f_sec {E1 (g (b,n)).1} (f1 (g (b,n)).1) @ i) (g (b,n)).2) >== inL (f (g (b,n))).1 ==< pmap inL (q b n) >== inL b `qed)) } \class POData { | X : \hType | Y : \hType | Q : X -> Y -> \hType \func PO => PushoutData {\Sigma (x : X) (y : Y) (Q x y)} __.1 __.2 \func swap (x : PO) : PushoutData {\Sigma (y : Y) (x : X) (Q x y)} __.1 __.2 | pinl b => pinr b | pinr c => pinl c | pglue (x,y,q) i => pglue (y,x,q) (inv (path (\lam j => j)) @ i) \func pbMap {x : X} {y : Y} (q : Q x y) : pinl x = {PO} pinr y => PushoutData.ppglue ((x,y,q) : \Sigma (x : X) (y : Y) (Q x y)) \lemma pullback_pushout-surjective (x : X) (y : Y) (p : pinl x = {PO} pinr y) : TruncP (\Sigma (x' : X) (Q x' y)) => \have | EP => \new EmbeddingPushout { | A => \Sigma (y : Y) (TruncP (\Sigma (x : X) (Q x y))) | B => PushoutData {\Sigma (x : X) (y : Y) (Q x y)} {X} {\Sigma (y : Y) (TruncP (\Sigma (x : X) (Q x y)))} __.1 (\lam p => (p.2, inP (p.1,p.3))) | C => Y | f => pinr | g => Embedding.projection (\lam y => TruncP (\Sigma (x : X) (Q x y))) } | t => ret {EP.pullback-path-equiv (pinl x) y} (pmap (\case __ \with { | pinl x => pinl (pinl x) | pinr y => pinr y | pglue (x,y,q) i => (pmap pinl (PushoutData.ppglue {\Sigma (x : X) (y : Y) (Q x y)} (x,y,q)) *> PushoutData.ppglue {EP.A} (y, inP (x,q))) @ i }) p) \in rewrite t.3 t.1.2 } \open POData \class Data \extends ReflUniverse, POData | ch {x x' : X} {y y' : Y} (q0 : Q x y) (q1 : Q x y') (q2 : Q x' y) : isConnectedType (Join (\Sigma (p : y = y') (transport (Q x) p q0 = q1)) (\Sigma (p : x = x') (transport (`Q y) p q0 = q2))) \class DataExt \extends Data { | x0 : X | y0 : Y | q0 : Q x0 y0 \func code-left {x : X} {w : PO} (p : pinl x = {PO} w) (p' : pinl x0 = w) : \hType => LType (\Sigma (q1 : Q x y0) (pbMap q0 *> inv (pbMap q1) *> p = p')) \func code-glue-gen {x : X} {w : PO} (code : pinl x0 = w -> \hType) (p : pinl x = w) (t : \Pi (p' : pinl x0 = w) -> Equiv {code-left p p'} {code p'}) : transport (pinl x0 = __ -> \hType) p (code-left idp) = code \elim p | idp => path (\lam i p' => Equiv-to-= (t p') @ i) \func code-glue {x : X} {y : Y} (q : Q x y) : transport (pinl x0 = __ -> \hType) (pbMap q) (code-left idp) = (\lam p => LType (Fib pbMap p)) => code-glue-gen (\lam p => LType (Fib pbMap p)) (pbMap q) (code.equiv q) \func code {w : PO} (p : pinl x0 = w) : \hType \elim w | pinl x => code-left idp p | pinr y => LType (Fib pbMap p) | pglue (x,y,q) i => (pathOver (code-glue q) @ i) p \where { \func equivData {x : X} {y : Y} (q : Q x y) (p : pinl x0 = {PO} pinr y) : EquivData \cowith | isLocal => isLocal | localization => localization | A => \Sigma (q1 : Q x y0) (pbMap q0 *> inv (pbMap q1) *> pbMap q = p) | B => Fib pbMap p | M a => \new Connected { | X => Join (\Sigma (p : y0 = y) (transport (Q x) p a.1 = q)) (\Sigma (p : x = x0) (transport (`Q y0) p a.1 = q0)) | connected => ch a.1 q q0 } | N b => \new Connected { | X => Join (\Sigma (p : y = y0) (transport (Q x0) p b.1 = q0)) (\Sigma (p : x0 = x) (transport (`Q y) p b.1 = q)) | connected => ch b.1 q0 q } | f ad => LR q p ad.1 ad.2 | g bd => RL q0 q p bd.1 bd.2 | p => LRL q p | q => RLR q p \lemma equiv {x : X} {y : Y} (q : Q x y) (p : pinl x0 = {PO} pinr y) => EquivData.equiv-lemma {equivData q p} \func pathLem1 {A : \hType} {a a' a'' : A} (p : a = a') (q : a'' = a') : p *> inv q *> q = p | idp, idp => idp \func pathLem2-gen {A : \hType} {a a' a'' : A} {p1 p2 : a = a'} {q : a = a''} (t : p1 *> inv p2 = idp) : p1 *> inv p2 *> q = q \elim q | idp => t \func pathLem2 {A : \hType} {a a' a'' : A} (p : a = a') (q : a = a'') : p *> inv p *> q = q => pathLem2-gen (*>_inv p) \func pathLem3 {A : \hType} {a a' : A} (p : a = a') : pathLem1 p p = pathLem2 p p | idp => idp \func LR {x : X} {y : Y} (q : Q x y) (p : pinl x0 = {PO} pinr y) (a : \Sigma (q1 : Q x y0) (pbMap q0 *> inv (pbMap q1) *> pbMap q = p)) (m : Join (\Sigma (p : y0 = y) (transport (Q x) p a.1 = q)) (\Sigma (p : x = x0) (transport (`Q y0) p a.1 = q0))) : \Sigma (b : Fib pbMap p) (Join (\Sigma (p : y = y0) (transport (Q x0) p b.1 = q0)) (\Sigma (p : x0 = x) (transport (`Q y) p b.1 = q))) \elim a, m | (a1,a2), jinl (idp,idp) => ((q0, inv (pathLem1 (pbMap q0) (pbMap a1)) *> a2), pinl (idp,idp)) | (a1,a2), jinr (idp,idp) => ((q, inv (pathLem2 (pbMap a1) (pbMap q)) *> a2), pinr (idp,idp)) | (a1,a2), pglue ((idp,idp),(idp,idp)) i => ((q0, inv (pathLem3 (pbMap q0) @ i) *> a2), pglue ((idp,idp),(idp,idp)) i) \func RL {x : X} {y : Y} (q0 : Q x0 y0) (q : Q x y) (p : pinl x0 = {PO} pinr y) (b : \Sigma (q2 : Q x0 y) (pbMap q2 = p)) (n : Join (\Sigma (p : y = y0) (transport (Q x0) p b.1 = q0)) (\Sigma (p : x0 = x) (transport (`Q y) p b.1 = q))) : \Sigma (a : \Sigma (q1 : Q x y0) (pbMap q0 *> inv (pbMap q1) *> pbMap q = p)) (Join (\Sigma (p : y0 = y) (transport (Q x) p a.1 = q)) (\Sigma (p : x = x0) (transport (`Q y0) p a.1 = q0))) \elim n | jinl (idp,idp) => ((q, pathLem1 (pbMap b.1) (pbMap q) *> b.2), pinl (idp,idp)) | jinr (idp,idp) => ((q0, pathLem2 (pbMap q0) (pbMap b.1) *> b.2), pinr (idp,idp)) | pglue ((idp,idp),(idp,idp)) i => ((b.1, (pathLem3 (pbMap b.1) @ i) *> b.2), pglue ((idp,idp),(idp,idp)) i) \func LRL {x : X} {y : Y} (q : Q x y) (p : pinl x0 = {PO} pinr y) (a : \Sigma (q1 : Q x y0) (pbMap q0 *> inv (pbMap q1) *> pbMap q = p)) (m : Join (\Sigma (p : y0 = y) (transport (Q x) p a.1 = q)) (\Sigma (p : x = x0) (transport (`Q y0) p a.1 = q0))) : (RL q0 q p (LR q p a m).1 (LR q p a m).2).1 = a \elim a, m | (a1,idp), jinl (idp,idp) => path (\lam i => (q, *>_inv (pathLem1 (pbMap q0) (pbMap q)) @ i)) | (a1,idp), jinr (idp,idp) => path (\lam i => (q0, *>_inv (pathLem2 (pbMap q0) (pbMap q)) @ i)) | (a1,idp), pglue ((idp,idp),(idp,idp)) j => path (\lam i => (q0, *>_inv (pathLem3 (pbMap q0) @ j) @ i)) \func RLR {x : X} {y : Y} (q : Q x y) (p : pinl x0 = {PO} pinr y) (b : \Sigma (q2 : Q x0 y) (pbMap q2 = p)) (n : Join (\Sigma (p : y = y0) (transport (Q x0) p b.1 = q0)) (\Sigma (p : x0 = x) (transport (`Q y) p b.1 = q))) : (LR q p (RL q0 q p b n).1 (RL q0 q p b n).2).1 = b \elim b, n | (b1,idp), jinl (idp,idp) => path (\lam i => (q0, inv_*> (pathLem1 (pbMap q0) (pbMap q)) @ i)) | (b1,idp), jinr (idp,idp) => path (\lam i => (q, inv_*> (pathLem2 (pbMap q0) (pbMap q)) @ i)) | (b1,idp), pglue ((idp,idp),(idp,idp)) j => path (\lam i => (q0, inv_*> (pathLem3 (pbMap q0) @ j) @ i)) } \func coerce-path-gen {w : PO} (p : pinl x0 = w) (t : transport (pinl x0 = __ -> \hType) p (code-left idp) = code) : code-left idp idp = code p \elim p | idp => path ((t @ __) idp) \func coerce-path {w : PO} (p : pinl x0 = w) : code-left idp idp = code p => coerce-path-gen p (pmapd (\lam _ => code) p) \func Left {w : PO} (p : pinl x0 = w) => \Sigma (q : Q x0 y0) (pbMap q0 *> inv (pbMap q) *> p = p) \func code-left-diag {w : PO} (p : pinl x0 = w) (v : code-left idp idp) : code-left p p => lmap {_} {Left idp} {Left p} (\lam t => (t.1, code.pathLem2-gen t.2)) v \func coerce-path-glue-gen {w : PO} (p : pinl x0 = w) (t : \Pi (p' : pinl x0 = w) -> Equiv {code-left p p'} {code p'}) (v : code-left idp idp) : transport (\lam T => T) (coerce-path-gen p (code-glue-gen code p t)) v = t p (code-left-diag p v) \elim p | idp => pmap (t idp) (inv (lmap.id-prop v)) \func code-center {w : PO} (p : pinl x0 = w) : code p => transport (\lam T => T) (coerce-path p) (lEta point) \where \func point : Left idp => (q0, *>_inv (pbMap q0)) \func code-path (p : pinl x0 = {PO} pinr y0) (c : Fib pbMap p) : code-center p = lEta c \elim c | (q,idp) => code-center (pbMap q) ==< pmap (\lam s => transport (\lam T => T) (coerce-path-gen (pbMap q) s) (lEta code-center.point)) (pmapd_pathOver (pinl x0 = __ -> \hType) (\lam _ => code) (pbMap q) (code-glue q) idp) >== transport (\lam T => T) (coerce-path-gen (pbMap q) (code-glue q)) (lEta code-center.point) ==< coerce-path-glue-gen (pbMap q) (code.equiv q) (lEta code-center.point) >== code.equiv q (pbMap q) (code-left-diag (pbMap q) (lEta code-center.point)) ==< pmap (code.equiv q (pbMap q)) (lift-prop (\lam (t : Left idp) => inL ((t.1, code.pathLem2-gen t.2) : Left (pbMap q))) code-center.point) >== code.equiv q (pbMap q) (lEta ((q0, code.pathLem2 (pbMap q0) (pbMap q)) : Left (pbMap q))) ==< EquivData.eval {code.equivData q (pbMap q)} (q0, code.pathLem2 (pbMap q0) (pbMap q)) (pinr (idp,idp)) >== lEta ((q, inv (code.pathLem2 (pbMap q0) (pbMap q)) *> code.pathLem2 (pbMap q0) (pbMap q)) : Fib pbMap p) ==< pmap (\lam x => lEta ((q,x) : Fib pbMap p)) (inv_*> (code.pathLem2 (pbMap q0) (pbMap q))) >== lEta ((q, idp) : Fib pbMap p) `qed \lemma code-contr {w : PO} (p : pinl x0 = w) : Contr (code p) \cowith | center => code-center p | contraction => transport (\lam t => \Pi (c : code t.2) -> code-center t.2 = c) (isContr=>isProp (lsigma {PO} (pinl x0)) (pinr y0, pbMap q0) (w, p)) (\lam c => remove_inL (\lam _ => code-center (pbMap q0)) (\lam c => c) (code-path (pbMap q0)) c) } }