{-# OPTIONS --lossy-unification #-} open import GpdCont.Prelude open import Cubical.Algebra.Group.Base using (GroupStr ; Group) open import Cubical.Algebra.Group.Properties using (module GroupTheory) open import Cubical.Algebra.Group.Morphisms using (GroupHom ; IsGroupHom ; GroupEquiv) open import Cubical.Algebra.Group.MorphismProperties using (isPropIsGroupHom ; makeIsGroupHom ; invGroupEquiv ; GroupEquiv→GroupHom) open import Cubical.Algebra.Group.GroupPath using (uaGroup) open import Cubical.Algebra.SymmetricGroup using (Symmetric-Group) module GpdCont.Delooping.Properties {ℓ} (G : Group ℓ) where open import GpdCont.Group.Solve using (solveGroup) private module G where open GroupStr (str G) public open GroupTheory G public reassoc : (g g′ h : ⟨ G ⟩) → g · (g′ · h · g) · g′ ≡ (g · g′) · h · (g · g′) reassoc = solveGroup G ·IdLR : (h : ⟨ G ⟩) → 1g · h · 1g ≡ h ·IdLR h = cong (1g ·_) (·IdR h) ∙ ·IdL h open G using (_·_ ; inv) open import GpdCont.Experimental.Groups.Base using () renaming (GroupStr to hGroupStr) open import GpdCont.Delooping.Base G as Delooping using (𝔹) open import GpdCont.Connectivity using (isPathConnected ; isPathConnected→merePath) open import GpdCont.Univalence using (ua→) import GpdCont.Group.FundamentalGroup as FundamentalGroup open import Cubical.Foundations.Equiv open import Cubical.Foundations.Equiv.Properties hiding (conjugatePathEquiv) open import Cubical.Foundations.HLevels open import Cubical.Foundations.Isomorphism open import Cubical.Foundations.GroupoidLaws open import Cubical.Foundations.Path using (compPath→Square) open import Cubical.Foundations.Univalence hiding (elimIso ; ua→) open import Cubical.Data.Sigma open import Cubical.HITs.SetTruncation as ST using (∥_∥₂) open import Cubical.HITs.PropositionalTruncation as PT using (∥_∥₁) open import Cubical.Functions.FunExtEquiv open import Cubical.Functions.Embedding isPropSetTruncDelooping : isProp ∥ 𝔹 ∥₂ isPropSetTruncDelooping = ST.elim2 (λ s t → ST.isSetPathImplicit) conn-lemma where conn-lemma : (s t : 𝔹) → ST.∣ s ∣₂ ≡ ST.∣ t ∣₂ conn-lemma = Delooping.elimProp {B = λ s → (t : 𝔹) → ST.∣ s ∣₂ ≡ ST.∣ t ∣₂} (λ s → isPropΠ λ t → ST.isSetSetTrunc _ _) (Delooping.elimProp (λ t → ST.isSetSetTrunc _ _) $ refl {x = ST.∣ Delooping.⋆ ∣₂}) isConnectedDelooping : isContr ∥ 𝔹 ∥₂ isConnectedDelooping = inhProp→isContr ST.∣ 𝔹.⋆ ∣₂ isPropSetTruncDelooping merePath : (x y : 𝔹) → ∥ x ≡ y ∥₁ merePath = isPathConnected→merePath isConnectedDelooping deloopingGroupStr : hGroupStr 𝔹 deloopingGroupStr .hGroupStr.is-connected = isConnectedDelooping deloopingGroupStr .hGroupStr.is-groupoid = Delooping.isGroupoid𝔹 deloopingGroupStr .hGroupStr.pt = Delooping.⋆ coerceLoopCompSquareFiller : ∀ {g h r} → g · h ≡ r → compSquareFiller (𝔹.loop g) (𝔹.loop h) (𝔹.loop r) coerceLoopCompSquareFiller {g} {h} {r} p i j = hcomp {φ = i ∨ ~ i ∨ j ∨ ~ j} (λ where k (i = i0) → Delooping.loop g j k (i = i1) → Delooping.loop (p k) j k (j = i0) → Delooping.⋆ k (j = i1) → Delooping.loop h i ) (𝔹.loop-comp g h i j) isPropDeloopingSquare : {x₀₀ x₀₁ : 𝔹} {x₀₋ : x₀₀ ≡ x₀₁} {x₁₀ x₁₁ : 𝔹} {x₁₋ : x₁₀ ≡ x₁₁} {x₋₀ : x₀₀ ≡ x₁₀} {x₋₁ : x₀₁ ≡ x₁₁} → isProp (Square x₀₋ x₁₋ x₋₀ x₋₁) isPropDeloopingSquare = isGroupoid→isPropSquare Delooping.isGroupoid𝔹 private conjugate : (g : ⟨ G ⟩) → ⟨ G ⟩ → ⟨ G ⟩ conjugate g h = inv g · h · g conjugateIso : (g : ⟨ G ⟩) → Iso ⟨ G ⟩ ⟨ G ⟩ conjugateIso g .Iso.fun = conjugate g conjugateIso g .Iso.inv = conjugate (inv g) conjugateIso g .Iso.rightInv h = inv g · (inv (inv g) · h · inv g) · g ≡[ i ]⟨ inv g · (G.invInv g i · h · inv g) · g ⟩ inv g · (g · (h · inv g)) · g ≡⟨ G.reassoc (inv g) g h ⟩ (inv g · g) · h · (inv g · g) ≡⟨ cong (λ - → - · h · -) (G.·InvL g) ⟩ G.1g · h · G.1g ≡⟨ G.·IdLR h ⟩ h ∎ conjugateIso g .Iso.leftInv h = inv (inv g) · (inv g · h · g) · inv g ≡⟨ cong (_· (inv g · h · g) · inv g) (G.invInv g) ⟩ g · (inv g · h · g) · inv g ≡⟨ G.reassoc g (inv g) h ⟩ (g · inv g) · h · (g · inv g) ≡⟨ cong (λ - → - · h · -) (G.·InvR g) ⟩ G.1g · h · G.1g ≡⟨ G.·IdLR h ⟩ h ∎ conjugateEquiv : (g : ⟨ G ⟩) → ⟨ G ⟩ ≃ ⟨ G ⟩ conjugateEquiv g = isoToEquiv $ conjugateIso g conjugatePath : (g : ⟨ G ⟩) → ⟨ G ⟩ ≡ ⟨ G ⟩ conjugatePath g = ua $ conjugateEquiv g conjugatePathFiller : ∀ g h → compSquareFiller (conjugatePath g) (conjugatePath h) (conjugatePath $ g · h) conjugatePathFiller g h = coerceCompSquareFiller $ ua (conjugateEquiv g) ∙ ua (conjugateEquiv h) ≡⟨ sym (uaCompEquiv _ _) ⟩ ua (conjugateEquiv g ∙ₑ conjugateEquiv h) ≡⟨ cong ua $ equivEq $ funExt shuffle ⟩ ua (conjugateEquiv $ g · h) ∎ where shuffle : ∀ x → inv h · (inv g · x · g) · h ≡ inv (g · h) · x · g · h shuffle x = inv h · (inv g · x · g) · h ≡⟨ lemma₁ (inv h) (inv g) x g h ⟩ (inv h · inv g) · x · g · h ≡⟨ cong (λ - → - · x · g · h) (sym $ G.invDistr g h) ⟩ inv (g · h) · x · g · h ∎ where lemma₁ : (h⁻¹ g⁻¹ x g h : ⟨ G ⟩) → h⁻¹ · (g⁻¹ · x · g) · h ≡ (h⁻¹ · g⁻¹) · x · g · h lemma₁ = solveGroup G mulRightIso : (g : ⟨ G ⟩) → Iso ⟨ G ⟩ ⟨ G ⟩ mulRightIso g .Iso.fun = _· g mulRightIso g .Iso.inv = _· (inv g) mulRightIso g .Iso.rightInv h = sym (G.·Assoc h (inv g) g) ∙ cong (h ·_) (G.·InvL g) ∙ G.·IdR h mulRightIso g .Iso.leftInv h = sym (G.·Assoc h g (inv g)) ∙ cong (h ·_) (G.·InvR g) ∙ G.·IdR h mulRightEquiv : (g : ⟨ G ⟩) → ⟨ G ⟩ ≃ ⟨ G ⟩ mulRightEquiv g = isoToEquiv $ mulRightIso g mulRightPath : (g : ⟨ G ⟩) → ⟨ G ⟩ ≡ ⟨ G ⟩ mulRightPath g = ua $ mulRightEquiv g opaque mulRightPathFiller : ∀ g h → compSquareFiller (mulRightPath g) (mulRightPath h) (mulRightPath $ g · h) mulRightPathFiller g h = coerceCompSquareFiller $ ua (mulRightEquiv g) ∙ ua (mulRightEquiv h) ≡⟨ sym (uaCompEquiv _ _) ⟩ ua (mulRightEquiv g ∙ₑ mulRightEquiv h) ≡⟨ cong ua $ equivEq $ funExt (λ k → sym (G.·Assoc k g h)) ⟩ ua (mulRightEquiv $ g · h) ∎ Code : 𝔹 → hSet ℓ Code = Delooping.rec isGroupoidHSet Code[⋆≡⋆] Code[⋆≡_] filler where Code[⋆≡⋆] : hSet ℓ Code[⋆≡⋆] .fst = ⟨ G ⟩ Code[⋆≡⋆] .snd = G.is-set Code[⋆≡_] : ⟨ G ⟩ → Code[⋆≡⋆] ≡ Code[⋆≡⋆] Code[⋆≡_] g = TypeOfHLevel≡ 2 (mulRightPath g) filler : ∀ g h → compSquareFiller Code[⋆≡ g ] Code[⋆≡ h ] Code[⋆≡ g · h ] filler g h = ΣSquareSet (λ _ → isProp→isSet isPropIsSet) (mulRightPathFiller g h) isSetCode : ∀ x → isSet ⟨ Code x ⟩ isSetCode = str ∘ Code encode : ∀ {y} → 𝔹.⋆ ≡ y → ⟨ Code y ⟩ encode = J (λ y p → ⟨ Code y ⟩) G.1g encodeRefl : encode refl ≡ G.1g encodeRefl = JRefl (λ y p → ⟨ Code y ⟩) G.1g decode : ∀ {y} → ⟨ Code y ⟩ → 𝔹.⋆ ≡ y decode {y} = decode' y where decode' : ∀ y → ⟨ Code y ⟩ → 𝔹.⋆ ≡ y decode' = Delooping.elimSet (λ x → isSet→ (𝔹.isGroupoid𝔹 𝔹.⋆ x)) 𝔹.loop λ { g → ua→ λ h → 𝔹.loop-comp h g } decode-encode : ∀ {y} (p : 𝔹.⋆ ≡ y) → decode (encode p) ≡ p decode-encode = J (λ y p → decode (encode p) ≡ p) $ decode (encode refl) ≡⟨ cong decode encodeRefl ⟩ decode G.1g ≡⟨ Delooping.loop-1 ⟩ refl ∎ encode-decode : ∀ y (c : ⟨ Code y ⟩) → encode (decode c) ≡ c encode-decode = Delooping.elimProp (λ _ → isPropΠ λ c → isSetCode _ _ _) λ g → transport refl (G.1g · g) ≡⟨ transportRefl _ ⟩ G.1g · g ≡⟨ G.·IdL g ⟩ g ∎ encodeDecodeIso : ∀ {y} → Iso (𝔹.⋆ ≡ y) ⟨ Code y ⟩ encodeDecodeIso .Iso.fun = encode encodeDecodeIso .Iso.inv = decode encodeDecodeIso .Iso.rightInv = encode-decode _ encodeDecodeIso .Iso.leftInv = decode-encode encodeDecode : ∀ {y} → (𝔹.⋆ ≡ y) ≃ ⟨ Code y ⟩ encodeDecode = isoToEquiv encodeDecodeIso ΩDelooping≃ : (𝔹.⋆ ≡ 𝔹.⋆) ≃ ⟨ G ⟩ ΩDelooping≃ = encodeDecode {y = 𝔹.⋆} unloop : 𝔹.⋆ ≡ 𝔹.⋆ → ⟨ G ⟩ unloop = equivFun ΩDelooping≃ loopEquiv : ⟨ G ⟩ ≃ (𝔹.⋆ ≡ 𝔹.⋆) loopEquiv = invEquiv ΩDelooping≃ isEquivLoop : isEquiv 𝔹.loop isEquivLoop = equivIsEquiv loopEquiv π₁ : (x₀ : 𝔹) → Group _ π₁ = FundamentalGroup.π₁ (𝔹 , 𝔹.isGroupoid𝔹) private π₁𝔹 : Group _ π₁𝔹 = π₁ 𝔹.⋆ conjugatePathEquiv : {x₀ x₁ : 𝔹} → x₀ ≡ x₁ → GroupEquiv (π₁ x₀) (π₁ x₁) conjugatePathEquiv = FundamentalGroup.conjugateGroupEquiv (𝔹 , 𝔹.isGroupoid𝔹) conjugatePathHom : {x₀ x₁ : 𝔹} → x₀ ≡ x₁ → GroupHom (π₁ x₀) (π₁ x₁) conjugatePathHom p = GroupEquiv→GroupHom $ conjugatePathEquiv p loopHom : GroupHom G π₁𝔹 loopHom .fst = 𝔹.loop loopHom .snd .IsGroupHom.pres· g h = sym $ Delooping.loop-∙ g h loopHom .snd .IsGroupHom.pres1 = Delooping.loop-1 loopHom .snd .IsGroupHom.presinv = Delooping.loop-inv loopGroupEquiv : GroupEquiv G π₁𝔹 loopGroupEquiv .fst = loopEquiv loopGroupEquiv .snd = loopHom .snd unloopGroupEquiv : GroupEquiv π₁𝔹 G unloopGroupEquiv = invGroupEquiv loopGroupEquiv unloopGroupHom : GroupHom π₁𝔹 G unloopGroupHom = GroupEquiv→GroupHom unloopGroupEquiv _ : unloopGroupHom .fst ≡ unloop _ = refl elimSetIso : ∀ {ℓB} {B : 𝔹 → Type ℓB} → (∀ x → isSet (B x)) → Iso (Σ[ b₀ ∈ B 𝔹.⋆ ] (∀ g → PathP (λ i → B (𝔹.loop g i)) b₀ b₀)) (∀ x → B x) elimSetIso is-set-B .Iso.fun = uncurry $ Delooping.elimSet is-set-B elimSetIso is-set-B .Iso.inv b = b 𝔹.⋆ , cong b ∘ 𝔹.loop elimSetIso is-set-B .Iso.rightInv b = funExt (Delooping.elimProp (λ _ → isOfHLevelPathP' 1 (is-set-B _) _ _) refl) elimSetIso is-set-B .Iso.leftInv (b₀ , p) = refl elimSetEquiv : ∀ {ℓB} {B : 𝔹 → Type ℓB} → (∀ x → isSet (B x)) → (Σ[ b₀ ∈ B 𝔹.⋆ ] (∀ g → PathP (λ i → B (𝔹.loop g i)) b₀ b₀)) ≃ (∀ x → B x) elimSetEquiv = isoToEquiv ∘ elimSetIso elimPropIso : ∀ {ℓB} {B : 𝔹 → Type ℓB} → (∀ x → isProp (B x)) → Iso (B 𝔹.⋆) (∀ x → B x) elimPropIso is-prop-B .Iso.fun = Delooping.elimProp is-prop-B elimPropIso is-prop-B .Iso.inv f = f 𝔹.⋆ elimPropIso is-prop-B .Iso.rightInv f = funExt λ x → is-prop-B _ _ (f x) elimPropIso is-prop-B .Iso.leftInv _ = refl elimPropEquiv : ∀ {ℓB} {B : 𝔹 → Type ℓB} → (∀ x → isProp (B x)) → (B 𝔹.⋆) ≃ (∀ x → B x) elimPropEquiv = isoToEquiv ∘ elimPropIso recEquiv : ∀ {ℓX} {X : hGroupoid ℓX} → (Σ[ x₀ ∈ ⟨ X ⟩ ] Σ[ φ ∈ (⟨ G ⟩ → x₀ ≡ x₀) ] ∀ g h → compSquareFiller (φ g) (φ h) (φ $ g · h)) ≃ (𝔹 → ⟨ X ⟩) recEquiv {X = (X , is-gpd-X)} = rec-equiv , is-equiv where open IsGroupHom using (pres·) rec-equiv : _ → _ rec-equiv (x₀ , φ , φ-hom) = Delooping.rec is-gpd-X x₀ φ φ-hom rec-inv : (𝔹 → X) → (Σ[ x₀ ∈ X ] Σ[ φ ∈ (⟨ G ⟩ → x₀ ≡ x₀) ] ∀ g h → compSquareFiller (φ g) (φ h) (φ $ g · h)) rec-inv f .fst = f 𝔹.⋆ rec-inv f .snd .fst = cong f ∘ 𝔹.loop rec-inv f .snd .snd = λ g h i j → f (Delooping.loop-comp g h i j) recIso : Iso _ _ recIso .Iso.fun = rec-equiv recIso .Iso.inv = rec-inv recIso .Iso.rightInv f = funExt (Delooping.elim (λ _ → isSet→isGroupoid (is-gpd-X _ _)) refl (λ g i j → f (𝔹.loop g i)) λ g h i j k → f (𝔹.loop-comp g h i j)) recIso .Iso.leftInv (x₀ , φ , φ-comp) = refl is-equiv : isEquiv rec-equiv is-equiv = isoToIsEquiv recIso recEquivHom : ∀ {ℓX} {X : hGroupoid ℓX} → (Σ[ x₀ ∈ ⟨ X ⟩ ] GroupHom G (FundamentalGroup.π₁ X x₀)) ≃ (𝔹 → ⟨ X ⟩) recEquivHom {X} = Σ-cong-equiv-snd (λ x₀ → Σ-cong-equiv-snd $ lemma x₀) ∙ₑ recEquiv where lemma : ∀ x₀ (φ : ⟨ G ⟩ → x₀ ≡ x₀) → IsGroupHom (str G) φ (FundamentalGroup.π₁ X x₀ .snd) ≃ ((g h : ⟨ G ⟩) → compSquareFiller (φ g) (φ h) (φ $ g · h)) lemma x₀ φ = propBiimpl→Equiv (isPropIsGroupHom _ _) (isPropΠ2 (λ g h → isGroupoid→isPropSquare (str X))) (λ is-hom g h → coerceCompSquareFiller (sym $ is-hom .IsGroupHom.pres· g h)) (λ mk-comp-sq → makeIsGroupHom λ g h → sym (compSquareFillerUnique (mk-comp-sq g h))) module _ {ℓ'} {B : 𝔹 → Type ℓ'} where cong⋆ : {f g : ∀ x → B x} (p : f ≡ g) → PathP (λ i → B 𝔹.⋆) (f 𝔹.⋆) (g 𝔹.⋆) cong⋆ = cong (λ f → f 𝔹.⋆) cong⋆-∙ : {f g h : ∀ x → B x} (p : f ≡ g) (q : g ≡ h) → cong⋆ (p ∙ q) ≡ cong⋆ p ∙ cong⋆ q cong⋆-∙ = cong-∙ (λ f → f 𝔹.⋆)