{-# OPTIONS --safe #-}

module Cubical.Homotopy.Loopspace where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Pointed
open import Cubical.Foundations.Pointed.Homogeneous
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.GroupoidLaws
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Equiv.HalfAdjoint
open import Cubical.Foundations.Function
open import Cubical.Foundations.Path

open import Cubical.Functions.Morphism

open import Cubical.Data.Nat
open import Cubical.Data.Sigma

open import Cubical.HITs.SetTruncation
open import Cubical.HITs.Truncation hiding (elim2) renaming (rec to trRec)

open Iso

{- loop space of a pointed type -}
Ω : { : Level}  Pointed   Pointed 
Ω (_ , a) = ((a  a) , refl)

{- n-fold loop space of a pointed type -}
Ω^_ :  {}    Pointed   Pointed 
(Ω^ 0) p = p
(Ω^ (suc n)) p = Ω ((Ω^ n) p)

{- loop space map -}
Ω→ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'}
       (A →∙ B)  (Ω A →∙ Ω B)
fst (Ω→ {A = A} {B = B} (f , p)) q = sym p ∙∙ cong f q ∙∙ p
snd (Ω→ {A = A} {B = B} (f , p)) = ∙∙lCancel p

Ω^→ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (n : )
   (A →∙ B)  ((Ω^ n) A →∙ (Ω^ n) B)
Ω^→ zero f = f
Ω^→ (suc n) f = Ω→ (Ω^→ n f)

{- loop space map functoriality (missing pointedness proof) -}
Ω→∘ :  { ℓ' ℓ''} {A : Pointed } {B : Pointed ℓ'} {C : Pointed ℓ''}
  (g : B →∙ C) (f : A →∙ B)
    p  Ω→ (g ∘∙ f) .fst p  (Ω→ g ∘∙ Ω→ f) .fst p
Ω→∘ g f p k i =
  hcomp
     j  λ
      { (i = i0)  compPath-filler' (cong (g .fst) (f .snd)) (g .snd) (~ k) j
      ; (i = i1)  compPath-filler' (cong (g .fst) (f .snd)) (g .snd) (~ k) j
      })
    (g .fst (doubleCompPath-filler (sym (f .snd)) (cong (f .fst) p) (f .snd) k i))

Ω→∘∙ :  { ℓ' ℓ''} {A : Pointed } {B : Pointed ℓ'} {C : Pointed ℓ''}
  (g : B →∙ C) (f : A →∙ B)
   Ω→ (g ∘∙ f)  (Ω→ g ∘∙ Ω→ f)
Ω→∘∙ g f = →∙Homogeneous≡ (isHomogeneousPath _ _) (funExt (Ω→∘ g f))

Ω→const :  { ℓ'} {A : Pointed } {B : Pointed ℓ'}
           Ω→ {A = A} {B = B} ((λ _  pt B) , refl)  ((λ _  refl) , refl)
Ω→const = →∙Homogeneous≡ (isHomogeneousPath _ _) (funExt λ _  sym (rUnit _))

{- Ω→ is a homomorphism -}
Ω→pres∙filler :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (f : A →∙ B)
         (p q : typ (Ω A))
         I  I  I  fst B
Ω→pres∙filler f p q i j k =
  hfill
     k  λ
       { (i = i0)  doubleCompPath-filler (sym (snd f)) (cong (fst f) (p  q)) (snd f) k j
        ; (i = i1) 
          (doubleCompPath-filler
            (sym (snd f)) (cong (fst f) p) (snd f) k
          doubleCompPath-filler
            (sym (snd f)) (cong (fst f) q) (snd f) k) j
       ; (j = i0)  snd f k
       ; (j = i1)  snd f k})
    (inS (cong-∙ (fst f) p q i j))
    k

Ω→pres∙ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (f : A →∙ B)
         (p q : typ (Ω A))
         fst (Ω→ f) (p  q)  fst (Ω→ f) p  fst (Ω→ f) q
Ω→pres∙ f p q i j = Ω→pres∙filler f p q i j i1

Ω→pres∙reflrefl :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (f : A →∙ B)
                   Ω→pres∙ {A = A} {B = B} f refl refl
                    cong (fst (Ω→ f)) (sym (rUnit refl))
                    snd (Ω→ f)
                    rUnit _
                    cong₂ _∙_ (sym (snd (Ω→ f))) (sym (snd (Ω→ f)))
Ω→pres∙reflrefl {A = A} {B = B} =
  →∙J  b₀ f  Ω→pres∙ {A = A} {B = (fst B , b₀)} f refl refl
                    cong (fst (Ω→ f)) (sym (rUnit refl))
                    snd (Ω→ f)
                    rUnit _
                    cong₂ _∙_ (sym (snd (Ω→ f))) (sym (snd (Ω→ f))))
       λ f  lem f
          cong (cong (fst (Ω→ (f , refl))) (sym (rUnit refl)) ∙_)
                (((lUnit (cong₂ _∙_ (sym (snd (Ω→ (f , refl))))
                                    (sym (snd (Ω→ (f , refl))))))
                 cong (_∙ (cong₂ _∙_ (sym (snd (Ω→ (f , refl))))
                                      (sym (snd (Ω→ (f , refl))))))
                   (sym (rCancel (snd (Ω→ (f , refl))))))
                 sym (assoc (snd (Ω→ (f , refl)))
                  (sym (snd (Ω→ (f , refl))))
                    (cong₂ _∙_ (sym (snd (Ω→ (f , refl))))
                               (sym (snd (Ω→ (f , refl)))))))
  where
  lem : (f : fst A  fst B)  Ω→pres∙ (f , refl)  _  snd A)  _  snd A) 
       i  fst (Ω→ (f , refl)) (rUnit  _  snd A) (~ i))) 
       i  snd (Ω→ (f , refl)) (~ i)  snd (Ω→ (f , refl)) (~ i))
  lem f k i j =
    hcomp  r  λ { (i = i0)  doubleCompPath-filler
                                   refl (cong f ((λ _  pt A)  refl)) refl (r  k) j
                    ; (i = i1)  (∙∙lCancel  _  f (pt A)) (~ r)
                                  ∙∙lCancel  _  f (pt A)) (~ r)) j
                    ; (j = i0)  f (snd A)
                    ; (j = i1)  f (snd A)
                    ; (k = i0)  Ω→pres∙filler {A = A} {B = fst B , f (pt A)}
                                   (f , refl) refl refl i j r
                    ; (k = i1)  compPath-filler
                                   ((λ i  fst (Ω→ (f , refl))
                                                (rUnit  _  snd A) (~ i))))
                                   ((λ i  snd (Ω→ (f , refl)) (~ i)
                                           snd (Ω→ (f , refl)) (~ i))) r i j})
     (hcomp  r  λ { (i = i0)  doubleCompPath-filler refl (cong f (rUnit  _  pt A) r)) refl k j
                    ; (i = i1)  rUnit  _  f (pt A)) (r  k) j
                    ; (j = i0)  f (snd A)
                    ; (j = i1)  f (snd A)
                    ; (k = i0)  cong-∙∙-filler f  _  pt A)  _  pt A)  _  pt A) r i j
                    ; (k = i1)  fst (Ω→ (f , refl)) (rUnit  _  snd A) (~ i  r)) j})
             (rUnit  _  f (pt A)) k j))

{- Ω^→ is homomorphism -}
Ω^→pres∙ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (f : A →∙ B)
         (n : )
         (p q : typ ((Ω^ (suc n)) A))
         fst (Ω^→ (suc n) f) (p  q)
          fst (Ω^→ (suc n) f) p  fst (Ω^→ (suc n) f) q
Ω^→pres∙ {A = A} {B = B} f n p q = Ω→pres∙ (Ω^→ n f) p q

Ω^→∘∙ :  { ℓ' ℓ''} {A : Pointed } {B : Pointed ℓ'} {C : Pointed ℓ''} (n : )
  (g : B →∙ C) (f : A →∙ B)
   Ω^→ n (g ∘∙ f)  (Ω^→ n g ∘∙ Ω^→ n f)
Ω^→∘∙ zero g f = refl
Ω^→∘∙ (suc n) g f = cong Ω→ (Ω^→∘∙ n g f)  Ω→∘∙ (Ω^→ n g) (Ω^→ n f)

Ω^→const :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (n : )
           Ω^→ {A = A} {B = B} n ((λ _  pt B) , refl)
           ((λ _  snd ((Ω^ n) B)) , refl)
Ω^→const zero = refl
Ω^→const (suc n) = cong Ω→ (Ω^→const n)  Ω→const

isEquivΩ→ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'}
            (f : (A →∙ B))
            isEquiv (fst f)  isEquiv (Ω→ f .fst)
isEquivΩ→ {B = (B , b)} =
  uncurry λ f 
    J  b y  isEquiv f
              isEquiv  q   i  y (~ i)) ∙∙  i  f (q i)) ∙∙ y))
      λ eqf  subst isEquiv (funExt (rUnit  cong f))
                     (isoToIsEquiv (congIso (equivToIso (f , eqf))))

isEquivΩ^→ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (n : )
            (f : A →∙ B)
            isEquiv (fst f)
            isEquiv (Ω^→ n f .fst)
isEquivΩ^→ zero f iseq = iseq
isEquivΩ^→ (suc n) f iseq = isEquivΩ→ (Ω^→ n f) (isEquivΩ^→ n f iseq)

Ω≃∙ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'}
      (e : A ≃∙ B)
      (Ω A) ≃∙ (Ω B)
fst (fst (Ω≃∙ e)) = fst (Ω→ (fst (fst e) , snd e))
snd (fst (Ω≃∙ e)) = isEquivΩ→ (fst (fst e) , snd e) (snd (fst e))
snd (Ω≃∙ e) = snd (Ω→ (fst (fst e) , snd e))

Ω≃∙pres∙ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'}
      (e : A ≃∙ B)
      (p q : typ (Ω A))
      fst (fst (Ω≃∙ e)) (p  q)
      fst (fst (Ω≃∙ e)) p
      fst (fst (Ω≃∙ e)) q
Ω≃∙pres∙ e p q = Ω→pres∙ (fst (fst e) , snd e) p q

Ω^≃∙ :  { ℓ'} {A : Pointed } {B : Pointed ℓ'} (n : )
      (e : A ≃∙ B)
      ((Ω^ n) A) ≃∙ ((Ω^ n) B)
Ω^≃∙ zero e = e
fst (fst (Ω^≃∙ (suc n) e)) =
  fst (Ω→ (fst (fst (Ω^≃∙ n e)) , snd (Ω^≃∙ n e)))
snd (fst (Ω^≃∙ (suc n) e)) =
  isEquivΩ→ (fst (fst (Ω^≃∙ n e)) , snd (Ω^≃∙ n e)) (snd (fst (Ω^≃∙ n e)))
snd (Ω^≃∙ (suc n) e) =
  snd (Ω→ (fst (fst (Ω^≃∙ n e)) , snd (Ω^≃∙ n e)))

ΩfunExtIso :  { ℓ'} (A : Pointed ) (B : Pointed ℓ')
   Iso (typ (Ω (A →∙ B ))) (A →∙ Ω B)
fst (fun (ΩfunExtIso A B) p) x = funExt⁻ (cong fst p) x
snd (fun (ΩfunExtIso A B) p) i j = snd (p j) i
fst (inv (ΩfunExtIso A B) (f , p) i) x = f x i
snd (inv (ΩfunExtIso A B) (f , p) i) j = p j i
rightInv (ΩfunExtIso A B) _ = refl
leftInv (ΩfunExtIso A B) _ = refl

relax→∙Ω-Iso :  { ℓ'} {A : Pointed } {B : Pointed ℓ'}
   Iso (Σ[ b  fst B ] (fst A  b  pt B))
         (A →∙ (Ω B))
Iso.fun (relax→∙Ω-Iso {A = A}) (b , p) =  a  sym (p (pt A))  p a) , lCancel (p (snd A))
Iso.inv (relax→∙Ω-Iso {B = B}) a = (pt B) , (fst a)
Iso.rightInv (relax→∙Ω-Iso) a =
  →∙Homogeneous≡ (isHomogeneousPath _ _)
    (funExt λ x  cong (_∙ fst a x) (cong sym (snd a))  sym (lUnit (fst a x)))
Iso.leftInv (relax→∙Ω-Iso {A = A}) (b , p) =
  ΣPathP (sym (p (pt A))
       , λ i a j  compPath-filler' (sym (p (pt A))) (p a) (~ i) j)


{- Commutativity of loop spaces -}
isComm∙ :  {} (A : Pointed )  Type 
isComm∙ A = (p q : typ (Ω A))  p  q  q  p

private
  mainPath :  {} {A : Pointed } (n : )  (α β : typ ((Ω^ (2 + n)) A))
             i  α i  refl)   i  refl  β i)
              i  refl  β i)   i  α i  refl)
  mainPath n α β i =  j  α (j  ~ i)  β (j  i))  λ j  α (~ i  j)  β (i  j)

EH-filler :  {} {A : Pointed } (n : )  typ ((Ω^ (2 + n)) A)
   typ ((Ω^ (2 + n)) A)  I  I  I  _
EH-filler {A = A} n α β i j z =
  hfill  k  λ { (i = i0)  ((cong  x  rUnit x (~ k)) α)
                                 cong  x  lUnit x (~ k)) β) j
                  ; (i = i1)  ((cong  x  lUnit x (~ k)) β)
                                 cong  x  rUnit x (~ k)) α) j
                  ; (j = i0)  rUnit refl (~ k)
                  ; (j = i1)  rUnit refl (~ k)})
        (inS (mainPath n α β i j)) z

{- Eckmann-Hilton -}
EH :  {} {A : Pointed } (n : )  isComm∙ ((Ω^ (suc n)) A)
EH {A = A} n α β i j = EH-filler n α β i j i1

{- Lemmas for the syllepsis : EH α β ≡ (EH β α) ⁻¹ -}

EH-refl-refl :  {} {A : Pointed } (n : )
              EH {A = A} n refl refl  refl
EH-refl-refl {A = A} n k i j =
  hcomp  r  λ { (k = i1)  (refl   _  basep)) j
                  ; (j = i0)  rUnit basep (~ r  ~ k)
                  ; (j = i1)  rUnit basep (~ r  ~ k)
                  ; (i = i0)  (refl   _  lUnit basep (~ r  ~ k))) j
                  ; (i = i1)  (refl   _  lUnit basep (~ r  ~ k))) j})
        (((cong  x  rUnit x (~ k))  _  basep))
          cong  x  lUnit x (~ k))  _  basep)) j)
  where
  basep = snd (Ω ((Ω^ n) A))

{- Generalisations of EH α β when α or β is refl -}
EH-gen-l :  {} {A : Pointed } (n : )  {x y : typ ((Ω^ (suc n)) A)} (α : x  y)
        α  refl  refl  α
EH-gen-l { = } {A = A} n {x = x} {y = y} α i j z =
  hcomp  k  λ { (i = i0)  ((cong  x  rUnit x (~ k)) α)  refl) j z
                  ; (i = i1)  (refl  cong  x  rUnit x (~ k)) α) j z
                  ; (j = i0)  rUnit (refl {x = x z}) (~ k) z
                  ; (j = i1)  rUnit (refl {x = y z}) (~ k) z
                  ; (z = i0)  x i1
                  ; (z = i1)  y i1})
        (((λ j  α (j  ~ i)  refl)  λ j  α (~ i  j)  refl) j z)

EH-gen-r :  {} {A : Pointed } (n : )  {x y : typ ((Ω^ (suc n)) A)} (β : x  y)
         refl  β  β  refl
EH-gen-r {A = A} n {x = x} {y = y} β i j z =
  hcomp  k  λ { (i = i0)  (refl  cong  x  lUnit x (~ k)) β) j z
                  ; (i = i1)  ((cong  x  lUnit x (~ k)) β)  refl) j z
                  ; (j = i0)  lUnit  k  x (k  z)) (~ k) z
                  ; (j = i1)  lUnit  k  y (k  z)) (~ k) z
                  ; (z = i0)  x i1
                  ; (z = i1)  y i1})
        (((λ j  refl  β (j  i))  λ j  refl  β (i  j)) j z)

{- characterisations of EH α β when α or β is refl  -}
EH-α-refl :  {} {A : Pointed } (n : )
              (α : typ ((Ω^ (2 + n)) A))
              EH n α refl  sym (rUnit α)  lUnit α
EH-α-refl {A = A} n α i j k =
  hcomp  r  λ { (i = i0)  EH-gen-l n  i  α (i  r)) j k
                  ; (i = i1)  (sym (rUnit λ i  α (i  r))  lUnit λ i  α (i  r)) j k
                  ; (j = i0)  ((λ i  α (i  r))  refl) k
                  ; (j = i1)  (refl   i  α (i  r))) k
                  ; (k = i0)  refl
                  ; (k = i1)  α r})
        ((EH-refl-refl n  sym (lCancel (rUnit refl))) i j k)

EH-refl-β :  {} {A : Pointed } (n : )
              (β : typ ((Ω^ (2 + n)) A))
              EH n refl β  sym (lUnit β)  rUnit β
EH-refl-β {A = A} n β i j k =
  hcomp  r  λ { (i = i0)  EH-gen-r n  i  β (i  r)) j k
                  ; (i = i1)  (sym (lUnit λ i  β (i  r))  rUnit λ i  β (i  r)) j k
                  ; (j = i0)  (refl   i  β (i  r))) k
                  ; (j = i1)  ((λ i  β (i  r))  refl) k
                  ; (k = i0)  refl
                  ; (k = i1)  β r})
        ((EH-refl-refl n  sym (lCancel (rUnit refl))) i j k)

syllepsis :  {} {A : Pointed } (n : ) (α β : typ ((Ω^ 3) A))
          EH 0 α β  sym (EH 0 β α)
syllepsis {A = A} n α β k i j =
  hcomp  r  λ { (i = i0)  i=i0 r j k
                  ; (i = i1)  i=i1 r j k
                  ; (j = i0)  j-filler r j k
                  ; (j = i1)  j-filler r j k
                  ; (k = i0)  EH-filler 1 α β i j r
                  ; (k = i1)  EH-filler 1 β α (~ i) j r})
        (btm-filler (~ k) i j)
  where
  guy = snd (Ω (Ω A))

  btm-filler : I  I  I  typ (Ω (Ω A))
  btm-filler j i k =
    hcomp  r
       λ {(j = i0)  mainPath 1 β α (~ i) k
          ; (j = i1)  mainPath 1 α β i k
          ; (i = i0)  (cong  x  EH-α-refl 0 x r (~ j)) α
                        cong  x  EH-refl-β 0 x r (~ j)) β) k
          ; (i = i1)  (cong  x  EH-refl-β 0 x r (~ j)) β
                        cong  x  EH-α-refl 0 x r (~ j)) α) k
          ; (k = i0)  EH-α-refl 0 guy r (~ j)
          ; (k = i1)  EH-α-refl 0 guy r (~ j)})
      (((λ l  EH 0 (α (l  ~ i)) (β (l  i)) (~ j))
        λ l  EH 0 (α (l  ~ i)) (β (l  i)) (~ j)) k)

  link : I  I  I  _
  link z i j =
    hfill  k  λ { (i = i1)  refl
                    ; (j = i0)  rUnit refl (~ i)
                    ; (j = i1)  lUnit guy (~ i  k)})
          (inS (rUnit refl (~ i  ~ j))) z

  i=i1 : I  I  I  typ (Ω (Ω A))
  i=i1 r j k =
    hcomp  i  λ { (r = i0)  (cong  x  compPath-filler (sym (lUnit x)) (rUnit x) i k) β
                                 cong  x  compPath-filler (sym (rUnit x)) (lUnit x) i k) α) j
                    ; (r = i1)  (β  α) j
                    ; (k = i0)  (cong  x  lUnit x (~ r)) β 
                                   cong  x  rUnit x (~ r)) α) j
                    ; (k = i1)  (cong  x  rUnit x (~ r  i)) β 
                                   cong  x  lUnit x (~ r  i)) α) j
                    ; (j = i0)  link i r k
                    ; (j = i1)  link i r k})
          (((cong  x  lUnit x (~ r  ~ k)) β
            cong  x  rUnit x (~ r  ~ k)) α)) j)

  i=i0 : I  I  I  typ (Ω (Ω A))
  i=i0 r j k =
    hcomp  i  λ { (r = i0)  (cong  x  compPath-filler (sym (rUnit x)) (lUnit x) i k) α
                                 cong  x  compPath-filler (sym (lUnit x)) (rUnit x) i k) β) j
                    ; (r = i1)  (α  β) j
                    ; (k = i0)  (cong  x  rUnit x (~ r)) α 
                                   cong  x  lUnit x (~ r)) β) j
                    ; (k = i1)  (cong  x  lUnit x (~ r  i)) α 
                                   cong  x  rUnit x (~ r  i)) β) j
                    ; (j = i0)  link i r k
                    ; (j = i1)  link i r k})
          ((cong  x  rUnit x (~ r  ~ k)) α
            cong  x  lUnit x (~ r  ~ k)) β) j)

  j-filler : I  I  I  typ (Ω (Ω A))
  j-filler r i k =
    hcomp  j  λ { (i = i0)  link j r k
                    ; (i = i1)  link j r k
                    ; (r = i0)  compPath-filler (sym (rUnit guy))
                                                  (lUnit guy) j k
                    ; (r = i1)  refl
                    ; (k = i0)  rUnit guy (~ r)
                    ; (k = i1)  rUnit guy (j  ~ r)})
          (rUnit guy (~ r  ~ k))

------ Ωⁿ⁺¹ A ≃ Ωⁿ(Ω A) ------
flipΩPath : { : Level} {A : Pointed } (n : )
                 ((Ω^ (suc n)) A)  (Ω^ n) (Ω A)
flipΩPath {A = A} zero = refl
flipΩPath {A = A} (suc n) = cong Ω (flipΩPath {A = A} n)

flipΩIso : { : Level} {A : Pointed } (n : )
               Iso (fst ((Ω^ (suc n)) A)) (fst ((Ω^ n) (Ω A)))
flipΩIso {A = A} n = pathToIso (cong fst (flipΩPath n))

flipΩIso⁻pres· : { : Level} {A : Pointed } (n : )
                       (f g : fst ((Ω^ (suc n)) (Ω A)))
                       inv (flipΩIso (suc n)) (f  g)
                       (inv (flipΩIso (suc n)) f)
                       (inv (flipΩIso (suc n)) g)
flipΩIso⁻pres· {A = A} n f g i =
    transp  j  flipΩPath {A = A} n (~ i  ~ j) .snd
                  flipΩPath n (~ i  ~ j) .snd) i
                  (transp  j  flipΩPath {A = A} n (~ i  ~ j) .snd
                  flipΩPath n (~ i  ~ j) .snd) (~ i) f
                  transp  j  flipΩPath {A = A} n (~ i  ~ j) .snd
                  flipΩPath n (~ i  ~ j) .snd) (~ i) g)

flipΩIsopres· : { : Level} {A : Pointed } (n : )
                       (f g : fst (Ω ((Ω^ (suc n)) A)))
                       fun (flipΩIso (suc n)) (f  g)
                       (fun (flipΩIso (suc n)) f)
                       (fun (flipΩIso (suc n)) g)
flipΩIsopres· n =
  morphLemmas.isMorphInv _∙_ _∙_
    (inv (flipΩIso (suc n)))
    (flipΩIso⁻pres· n)
    (fun (flipΩIso (suc n)))
    (Iso.leftInv (flipΩIso (suc n)))
    (Iso.rightInv (flipΩIso (suc n)))

flipΩrefl :  {} {A : Pointed } (n : )
   fun (flipΩIso {A = A} (suc n)) refl  refl
flipΩrefl {A = A} n j =
  transp  i₁  fst (Ω (flipΩPath {A = A} n ((i₁  j)))))
         j (snd (Ω (flipΩPath n j)))

---- Misc. ----

isCommA→isCommTrunc :  {} {A : Pointed } (n : )  isComm∙ A
                     isOfHLevel (suc n) (typ A)
                     isComm∙ ( typ A  (suc n) ,  pt A )
isCommA→isCommTrunc {A = (A , a)} n comm hlev p q =
    ((λ i j  (leftInv (truncIdempotentIso (suc n) hlev) ((p  q) j) (~ i)))
 ∙∙  i  cong {B = λ _   A  (suc n) }  x   x )
                 (cong (trRec hlev  x  x)) (p  q)))
 ∙∙  i  cong {B = λ _   A  (suc n) }  x   x )
                 (congFunct {A =  A  (suc n)} {B = A} (trRec hlev  x  x)) p q i)))
  ((λ i  cong {B = λ _   A  (suc n) }  x   x )
                 (comm (cong (trRec hlev  x  x)) p) (cong (trRec hlev  x  x)) q) i))
 ∙∙  i  cong {B = λ _   A  (suc n) }  x   x )
                 (congFunct {A =  A  (suc n)} {B = A} (trRec hlev  x  x)) q p (~ i)))
 ∙∙  i j  (leftInv (truncIdempotentIso (suc n) hlev) ((q  p) j) i)))

ptdIso→comm :  { ℓ'} {A : Pointed } {B : Type ℓ'} (e : Iso (typ A) B)
   isComm∙ A  isComm∙ (B , fun e (pt A))
ptdIso→comm {A = (A , a)} {B = B} e comm p q =
       sym (rightInv (congIso e) (p  q))
    ∙∙ (cong (fun (congIso e)) ((invCongFunct e p q)
                            ∙∙ (comm (inv (congIso e) p) (inv (congIso e) q))
                            ∙∙ (sym (invCongFunct e q p))))
    ∙∙ rightInv (congIso e) (q  p)

{- Homotopy group version -}
π-comp :  {} {A : Pointed } (n : )   typ ((Ω^ (suc n)) A) ∥₂
        typ ((Ω^ (suc n)) A) ∥₂   typ ((Ω^ (suc n)) A) ∥₂
π-comp n = elim2  _ _  isSetSetTrunc) λ p q   p  q ∣₂

EH-π :  {} {A : Pointed } (n : ) (p q :  typ ((Ω^ (2 + n)) A) ∥₂)
                π-comp (1 + n) p q  π-comp (1 + n) q p
EH-π  n = elim2  x y  isOfHLevelPath 2 isSetSetTrunc _ _)
                             λ p q  cong ∣_∣₂ (EH n p q)