{-# OPTIONS --without-K --rewriting --overlapping-instances #-}

open import lib.Basics
open import lib.Equivalence2
open import lib.NType2
open import lib.FTID
open import lib.types.Bool
open import lib.types.Empty
open import lib.types.Paths
open import lib.types.Pi
open import lib.types.Sigma

{-
This file contains various lemmas that rely on lib.types.Paths or
functional extensionality for pointed maps.
-}

module lib.types.Pointed where

{- Pointed maps -}

⊙app= :  {i j} {X : Ptd i} {Y : Ptd j} {f g : X ⊙→ Y}
   f == g  f ⊙∼ g
⊙app= {X = X} {Y = Y} p =
  app= (fst= p) , ↓-ap-in (_== pt Y)  u  u (pt X)) (snd= p)

-- function extensionality for pointed maps
⊙λ= :  {i j} {X : Ptd i} {Y : Ptd j} {f g : X ⊙→ Y}
   f ⊙∼ g  f == g
⊙λ= {g = g} (p , α) = pair= (λ= p)
  (↓-app=cst-in (↓-idf=cst-out α  ap (_∙ snd g) (! (app=-β p _))))

⊙λ=' :  {i j} {X : Ptd i} {Y : Ptd j} {f g : X ⊙→ Y}
  (p : fst f  fst g)
  (α : snd f == snd g [  y  y == pt Y)  p (pt X) ])
   f == g
⊙λ=' {g = g} = curry ⊙λ=

-- associativity of pointed maps
⊙∘-assoc-pt :  {i j k} {A : Type i} {B : Type j} {C : Type k}
  {a₁ a₂ : A} (f : A  B) {b : B} (g : B  C) {c : C}
  (p : a₁ == a₂) (q : f a₂ == b) (r : g b == c)
   ⊙∘-pt (g  f) p (⊙∘-pt g q r) == ⊙∘-pt g (⊙∘-pt f p q) r
⊙∘-assoc-pt _ _ idp _ _ = idp

⊙∘-assoc :  {i j k l} {X : Ptd i} {Y : Ptd j} {Z : Ptd k} {W : Ptd l}
  (h : Z ⊙→ W) (g : Y ⊙→ Z) (f : X ⊙→ Y)
   ((h ⊙∘ g) ⊙∘ f) ⊙∼ (h ⊙∘ (g ⊙∘ f))
⊙∘-assoc (h , hpt) (g , gpt) (f , fpt) =  _  idp) , ⊙∘-assoc-pt g h fpt gpt hpt

⊙∘-cst-l :  {i j k} {X : Ptd i} {Y : Ptd j} {Z : Ptd k}
   (f : X ⊙→ Y)  (⊙cst :> (Y ⊙→ Z)) ⊙∘ f ⊙∼ ⊙cst
⊙∘-cst-l {Z = Z} f =  _  idp) , ap (_∙ idp) (ap-cst (pt Z) (snd f))

⊙∘-cst-r :  {i j k} {X : Ptd i} {Y : Ptd j} {Z : Ptd k}
   (f : Y ⊙→ Z)  f ⊙∘ (⊙cst :> (X ⊙→ Y)) ⊙∼ ⊙cst
⊙∘-cst-r {X = X} f =  _  snd f) , ↓-idf=cst-in' idp

module _ {i j} {X : Ptd i} {Y : Ptd j} (f : X ⊙→ Y) where

  ⊙∘-lunit : f ⊙-crd∼ ⊙idf Y ⊙∘ f
  fst ⊙∘-lunit x = idp
  snd ⊙∘-lunit = ! (∙-unit-r (ap  x  x) (snd f))  ap-idf (snd f))

  ⊙∘-runit : f ⊙-crd∼ f ⊙∘ ⊙idf X
  fst ⊙∘-runit x = idp
  snd ⊙∘-runit = idp

module _ {i j} {X : Ptd i} {Y : Ptd j} where

  -- inverse of homotopy of pointed maps
  !-⊙∼ : {f₁ f₂ : X ⊙→ Y} (H : f₁ ⊙-crd∼ f₂)  f₂ ⊙-crd∼ f₁
  fst (!-⊙∼ (H₀ , H₁)) x = ! (H₀ x)
  snd (!-⊙∼ {f₁} {f₂} (H₀ , H₁)) =
    ap  p  p  snd f₂) (!-! (H₀ (pt (X)))) 
    ap  p  H₀ (pt X)  p) (! H₁) 
    ! (∙-assoc (H₀ (pt X)) (! (H₀ (pt X))) (snd f₁)) 
    ap  p  p  snd f₁) (!-inv-r (H₀ (pt X)))

-- identity homotopy of pointed maps
  ⊙∼-id : (f : X ⊙→ Y)  f ⊙-crd∼ f
  fst (⊙∼-id (f , fₚ)) x = idp
  snd (⊙∼-id (f , fₚ)) = idp

module _ {i j k} {X : Ptd i} {Y : Ptd j} {Z : Ptd k} where 

  -- associativity of pointed maps (in the other direction than before)
  ⊙∘-α-crd :  {l} {W : Ptd l} (h : Z ⊙→ W) (g : Y ⊙→ Z) (f : X ⊙→ Y)
     h ⊙∘ g ⊙∘ f ⊙-crd∼ (h ⊙∘ g) ⊙∘ f
  fst (⊙∘-α-crd h g f) _ = idp
  snd (⊙∘-α-crd h g f) =
    ap  p  p  snd h) (ap-∘-∙ (fst h) (fst g) (snd f) (snd g)) 
    ∙-assoc (ap (fst h  fst g) (snd f)) (ap (fst h) (snd g)) (snd h)

-- pre- and post-comp on (unfolded) homotopies of pointed maps

  ⊙∘-post : {f₁ f₂ : X ⊙→ Y} (g : Y ⊙→ Z) (H : f₁ ⊙-crd∼ f₂)  g ⊙∘ f₁ ⊙-crd∼ g ⊙∘ f₂
  fst (⊙∘-post g H) = λ x  ap (fst g) (fst H x)
  snd (⊙∘-post {f₁} g H) =
    ! (∙-assoc (! (ap (fst g) (fst H (pt X)))) (ap (fst g) (snd f₁)) (snd g)) 
    ap  p  p  snd g) (!-ap-∙ (fst g) (fst H (pt X)) (snd f₁)) 
    ap  p  p  snd g) (ap (ap (fst g)) (snd H))

  ⊙∘-pre : {f₁ f₂ : X ⊙→ Y} (g : Z ⊙→ X) (H : f₁ ⊙-crd∼ f₂)  f₁ ⊙∘ g ⊙-crd∼ f₂ ⊙∘ g
  fst (⊙∘-pre g H) = λ x  fst H (fst g x)
  snd (⊙∘-pre {f₁} {f₂} g H) =
    ! (∙-assoc (! (fst H (fst g (pt Z)))) (ap (fst f₁) (snd g)) (snd f₁)) 
    ap  p  p  snd f₁) (hmtpy-nat-!-sq (fst H) (snd g)) 
    ∙-assoc (ap (fst f₂) (snd g)) (! (fst H (pt X))) (snd f₁) 
    ap  p  ap (fst f₂) (snd g)  p) (snd H)
    
-- concatenation of homotopies of pointed maps

module _ {i j} {X : Ptd i} {Y : Ptd j} {f₁ f₂ f₃ : X ⊙→ Y} where 

  infixr 15 _∙⊙∼_
  _∙⊙∼_ : f₁ ⊙-crd∼ f₂  f₂ ⊙-crd∼ f₃  f₁ ⊙-crd∼ f₃
  fst (H₁ ∙⊙∼ H₂) = λ x  fst H₁ x  fst H₂ x 
  snd (H₁ ∙⊙∼ H₂) =
    ap  p  ! (p  fst H₂ (pt X))  snd f₁) (tri-exch (snd H₁))  
    ap  p  ! ((snd f₁  ! (snd f₂))  p)  snd f₁) (tri-exch (snd H₂)) 
    !3-∙3 (snd f₁) (snd f₂) (snd f₃)

-- homotopies of homotopies of pointed maps

module _ {i j} {X : Ptd i} {Y : Ptd j} where

  infixr 10 _⊙→∼_
  _⊙→∼_ : {f g : X ⊙→ Y} (H₁ H₂ : f ⊙-crd∼ g)  Type (lmax i j)
  _⊙→∼_ {f = f} H₁ H₂ =
    Σ (fst H₁  fst H₂)
       K  ap  p   ! p  snd f) (K (pt X))  snd H₂ == snd H₁)

  ⊙→∼-id : {f g : X ⊙→ Y} (H : f ⊙-crd∼ g)  H ⊙→∼ H
  fst (⊙→∼-id H) = λ x  idp
  snd (⊙→∼-id H) = idp

-- pointed sections

  record has-sect⊙ (f : X ⊙→ Y) : Type (lmax i j) where
    constructor sect⊙
    field
      r-inv : Y ⊙→ X
      sect⊙-eq : f ⊙∘ r-inv == ⊙idf Y

-- induction principle for ⊙-crd∼

module _ {i j} {X : Ptd i} {Y : Ptd j} (f : X ⊙→ Y) where

  ⊙hom-contr-aux :
    is-contr
      (Σ (Σ (de⊙ X  de⊙ Y)  g  fst f  g))
         (h , K)  Σ (h (pt X) == pt Y)  p  (! (K (pt X))  snd f == p))))
  ⊙hom-contr-aux =
    equiv-preserves-level
      ((Σ-contr-red
        {P = λ (h , K)  Σ (h (pt X) == pt Y)  p  (! (K (pt X))  snd f == p))}
        (funhom-contr {f = fst f}))⁻¹)

  abstract
    ⊙hom-contr : is-contr (Σ (X ⊙→ Y)  g  f ⊙-crd∼ g))
    ⊙hom-contr = equiv-preserves-level lemma {{⊙hom-contr-aux}}
      where
        lemma :
          Σ (Σ (de⊙ X  de⊙ Y)  g  fst f  g))
             (h , K)  Σ (h (pt X) == pt Y)  p  (! (K (pt X))  snd f == p)))
            
          Σ (X ⊙→ Y)  g  f ⊙-crd∼ g)
        lemma =
          equiv
             ((g , K) , (p , H))  (g , p) , (K , H))
             ((h , p) , (H , K))  (h , H) , (p , K))
             ((h , p) , (H , K))  idp)
            λ ((g , K) , (p , H))  idp

  ⊙hom-ind :  {k} (P : (g : X ⊙→ Y)  (f ⊙-crd∼ g  Type k))
     P f (⊙∼-id f)  {g : X ⊙→ Y} (p : f ⊙-crd∼ g)  P g p
  ⊙hom-ind P = ID-ind-map P ⊙hom-contr

  ⊙hom-ind-β :  {k} (P : (g : X ⊙→ Y)  (f ⊙-crd∼ g  Type k))
     (r : P f (⊙∼-id f))  ⊙hom-ind P r {f} (⊙∼-id f) == r
  ⊙hom-ind-β P = ID-ind-map-β P ⊙hom-contr

module _ {i j} {X : Ptd i} {Y : Ptd j} where

  ⊙-crd∼-to-== : {f g : X ⊙→ Y}  f ⊙-crd∼ g  f == g
  ⊙-crd∼-to-== {f} = ⊙hom-ind f  g _  f == g) idp

  ⊙-crd∼-to-==-β : (f : X ⊙→ Y)  ⊙-crd∼-to-== (⊙∼-id f) == idp
  ⊙-crd∼-to-==-β f = ⊙hom-ind-β f  g _  f == g) idp

  ==-to-⊙-crd∼ : {f g : X ⊙→ Y}  f == g  f ⊙-crd∼ g
  ==-to-⊙-crd∼ idp = ⊙∼-id _

  ⊙-crd∼-==-≃ : {f g : X ⊙→ Y}  (f == g)  (f ⊙-crd∼ g)
  ⊙-crd∼-==-≃ {f} {g} = equiv ==-to-⊙-crd∼ ⊙-crd∼-to-== aux1 aux2
    where
      aux1 : {k : X ⊙→ Y} (H : f ⊙-crd∼ k)  ==-to-⊙-crd∼ (⊙-crd∼-to-== H) == H
      aux1 =
        ⊙hom-ind f  k H  ==-to-⊙-crd∼ (⊙-crd∼-to-== H) == H)
          (ap (==-to-⊙-crd∼) (⊙-crd∼-to-==-β f))

      aux2 : {k : X ⊙→ Y} (p : f == k)  ⊙-crd∼-to-== (==-to-⊙-crd∼ p) == p
      aux2 idp = ⊙-crd∼-to-==-β f 

-- some groupoid laws obeyed by ==-to-⊙-crd∼

  ==-to-⊙-crd∼-∙ : {f g h : X ⊙→ Y} (p : f == g) (q : g == h)  ==-to-⊙-crd∼ (p  q) == (==-to-⊙-crd∼ p ∙⊙∼ ==-to-⊙-crd∼ q)
  ==-to-⊙-crd∼-∙ {(_ , idp)} idp idp = idp

  ==-to-⊙-crd∼-∙2 : {f g h k : X ⊙→ Y} (p : f == g) (q : g == h) (r : h == k) 
    ==-to-⊙-crd∼ (p  q  r) == (==-to-⊙-crd∼ p ∙⊙∼ ==-to-⊙-crd∼ q ∙⊙∼ ==-to-⊙-crd∼ r)
  ==-to-⊙-crd∼-∙2 {(_ , idp)} idp idp idp = idp

module _ {i j k} {X : Ptd i} {Y : Ptd j} {Z : Ptd k} where

  ==-to-⊙-crd∼-whisk-r : {h : Z ⊙→ X} {f g : X ⊙→ Y} (p : f == g) 
    ==-to-⊙-crd∼ (ap  m  m ⊙∘ h) p) == (⊙∘-pre h (==-to-⊙-crd∼ p))
  ==-to-⊙-crd∼-whisk-r {(_ , idp)} idp = idp 

  ==-to-⊙-crd∼-whisk-l : {h : Y ⊙→ Z} {f g : X ⊙→ Y} (p : f == g) 
    ==-to-⊙-crd∼ (ap  m  h ⊙∘ m) p) == (⊙∘-post h (==-to-⊙-crd∼ p))
  ==-to-⊙-crd∼-whisk-l {(_ , idp)} idp = idp 

-- induction principle for ⊙∼→

module _ {i j} {X : Ptd i} {Y : Ptd j} {f₁ f₂ : X ⊙→ Y} {H : f₁ ⊙-crd∼ f₂} where

  ⊙→∼-contr-aux :
    is-contr $
      Σ (Σ (fst f₁  fst f₂)  h  fst H  h))
         (h , k)  Σ (! (h (pt X))  snd f₁ == snd f₂)
           L  ap  p   ! p  snd f₁) (k (pt X))  L == snd H))
  ⊙→∼-contr-aux =
    equiv-preserves-level
      ((Σ-contr-red
        {P = λ (h , k) 
          Σ (! (h (pt X))  snd f₁ == snd f₂)  L  ap  p   ! p  snd f₁) (k (pt X))  L == snd H)}
        (funhom-contr {f = fst H}))⁻¹)

  abstract
    ⊙→∼-contr : is-contr (Σ (f₁ ⊙-crd∼ f₂)  K  H ⊙→∼ K))
    ⊙→∼-contr = equiv-preserves-level lemma {{⊙→∼-contr-aux}}
      where
        lemma :
          Σ (Σ (fst f₁  fst f₂)  h  fst H  h))
             (h , k)  Σ (! (h (pt X))  snd f₁ == snd f₂)
               L  ap  p   ! p  snd f₁) (k (pt X))  L == snd H))
            
          Σ (f₁ ⊙-crd∼ f₂)  K  H ⊙→∼ K)
        lemma =
          equiv
             ((h , k) , (L , c))  (h , L) , (k , c))
             ((K₁ , K₂) , (c₁ , c₂))  (K₁ , c₁) , (K₂ , c₂))
             ((K₁ , K₂) , (c₁ , c₂))  idp)
            λ ((h , k) , (L , c))  idp

  ⊙→∼-ind :  {k} (P : (K : f₁ ⊙-crd∼ f₂)  (H ⊙→∼ K  Type k))
     P H (⊙→∼-id H)  {K : f₁ ⊙-crd∼ f₂} (p : H ⊙→∼ K)  P K p
  ⊙→∼-ind P = ID-ind-map P ⊙→∼-contr

module _ {i j} {X : Ptd i} {Y : Ptd j} {f g : X ⊙→ Y} {H₁ H₂ : f ⊙-crd∼ g} where

  ⊙→∼-to-== : H₁ ⊙→∼ H₂  H₁ == H₂
  ⊙→∼-to-== = ⊙→∼-ind {H = H₁}  H₂ _  H₁ == H₂) idp 

module _ {i j} {X : Ptd i} {Y : Ptd j} where

  ∙⊙∼-! : (f : X ⊙→ Y)  !-⊙∼ (⊙∼-id f) == ⊙∼-id f
  ∙⊙∼-! (f₀ , idp) = ⊙→∼-to-== ((λ _  idp) , idp)

  ∙⊙∼-unit-l : {f g : X ⊙→ Y} (H : f ⊙-crd∼ g)  (⊙∼-id f ∙⊙∼ H) == H
  ∙⊙∼-unit-l {f = (f₀ , idp)} H = ⊙→∼-to-== ((λ _  idp) , aux (snd H))
    where
      aux :  {k} {A : Type k} {x y : A} {r : y == x} {q₂ : x == y} (q₁ : ! r  idp == q₂) 
        q₁ == ap  p  ! p  idp) (tri-exch q₁)  ∙-unit-r (! (! q₂))  !-! q₂
      aux {r = idp} idp = idp

  ∙⊙∼-unit-r : {f g : X ⊙→ Y} (H : f ⊙-crd∼ g)→ (H ∙⊙∼ ⊙∼-id g) == H
  ∙⊙∼-unit-r {g = (g₀ , idp)} H = ⊙→∼-to-== ((λ x  ∙-unit-r (fst H x)) , aux {r = fst H (pt X)} (snd H))
    where
      aux :  {k} {A : Type k} {x y : A} {r q₂ : x == y} (q₁ : ! r  q₂ == idp) 
        ap  p  ! p  q₂) (∙-unit-r r)  q₁
          ==
        ap  p  ! (p  idp)  q₂) (tri-exch q₁)  !3-∙3 q₂ idp idp
      aux {r = idp} idp = idp

module _ {i j k} {X : Ptd i} {Y : Ptd j} {Z : Ptd k} where

  ∙⊙-post : {f : X ⊙→ Y} {g : Y ⊙→ Z}  ⊙∘-post g (⊙∼-id f) == ⊙∼-id (g ⊙∘ f)
  ∙⊙-post = ⊙→∼-to-== ((λ _  idp) , idp)

  ∙⊙-pre : {f : X ⊙→ Y} {g : Z ⊙→ X}  ⊙∘-pre g (⊙∼-id f) == ⊙∼-id (f ⊙∘ g)
  ∙⊙-pre {g = (g₀ , idp)} = ⊙→∼-to-== ((λ _  idp) , idp)

{- Pointed equivalences -}

-- equality of pointed equivalences
⊙≃-== :  {i j} {X : Ptd i} {Y : Ptd j} {τ₁ τ₂ : X ⊙≃ Y}  (fst τ₁ == fst τ₂)  (τ₁ == τ₂)
⊙≃-== {τ₁ = τ₁} {τ₂} = =Σ-econv τ₁ τ₂ ∘e equiv  e  e , prop-has-all-paths-↓) fst
   _  pair= idp (prop-has-all-paths {{↓-level}} _ _)) λ _  idp

-- Extracting data from an pointed equivalence
module _ {i j} {X : Ptd i} {Y : Ptd j} (⊙e : X ⊙≃ Y) where

  ⊙≃-to-≃ : de⊙ X  de⊙ Y
  ⊙≃-to-≃ = fst (fst ⊙e) , snd ⊙e

  ⊙–> : X ⊙→ Y
  ⊙–> = fst ⊙e

  ⊙–>-pt = snd ⊙–>

  ⊙<– : Y ⊙→ X
  ⊙<– = is-equiv.g (snd ⊙e) , lemma ⊙e
    module ⊙e-rev where
      lemma : {Y : Ptd j} (⊙e : X ⊙≃ Y)  is-equiv.g (snd ⊙e) (pt Y) == pt X
      lemma ((f , idp) , f-ise) = is-equiv.g-f f-ise (pt X)

  ⊙<–-pt = snd ⊙<–

  infix 120 _⊙⁻¹
  _⊙⁻¹ : Y ⊙≃ X
  _⊙⁻¹ = ⊙<– , is-equiv-inverse (snd ⊙e)

module _ {i j} {X : Ptd i} {Y : Ptd j} where 

  ⊙<–-inv-l : (⊙e : X ⊙≃ Y)  ⊙<– ⊙e ⊙∘ ⊙–> ⊙e ⊙∼ ⊙idf _
  ⊙<–-inv-l ⊙e = <–-inv-l (⊙≃-to-≃ ⊙e) , ↓-idf=cst-in' (lemma ⊙e) where
    lemma : {Y : Ptd j} (⊙e : X ⊙≃ Y)
       snd (⊙<– ⊙e ⊙∘ ⊙–> ⊙e) == is-equiv.g-f (snd ⊙e) (pt X)
    lemma ((f , idp) , f-ise) = idp

  ⊙<–-inv-l-comp : (⊙e : X ⊙≃ Y)  ⊙<– ⊙e ⊙∘ ⊙–> ⊙e ⊙-crd∼ ⊙idf _
  ⊙<–-inv-l-comp ⊙e = ⊙-to-crd (⊙<–-inv-l ⊙e)

  ⊙<–-inv-r : (⊙e : X ⊙≃ Y)  ⊙–> ⊙e ⊙∘ ⊙<– ⊙e ⊙∼ ⊙idf _
  ⊙<–-inv-r ⊙e = <–-inv-r (⊙≃-to-≃ ⊙e) , ↓-idf=cst-in' (lemma ⊙e) where
    lemma : {Y : Ptd j} (⊙e : X ⊙≃ Y)
       snd (⊙–> ⊙e ⊙∘ ⊙<– ⊙e) == is-equiv.f-g (snd ⊙e) (pt Y)
    lemma ((f , idp) , f-ise) = ∙-unit-r _  is-equiv.adj f-ise (pt X)

module _ {i j k} {X : Ptd i} {Y : Ptd j} {Z : Ptd k} (⊙e : X ⊙≃ Y) where

  post⊙∘-is-equiv : is-equiv  (k : Z ⊙→ X)  ⊙–> ⊙e ⊙∘ k)
  post⊙∘-is-equiv = is-eq (⊙–> ⊙e ⊙∘_) (⊙<– ⊙e ⊙∘_) (to-from ⊙e) (from-to ⊙e) where
    abstract
      to-from : {Y = Y₁ : Ptd j} (⊙e₁ : _⊙≃_ {i} {j} X Y₁)
                (k₁ : _⊙→_ {k} {j} Z Y₁) 
                _==_ {lmax j k}
                {Σ {lmax j k} {j} (de⊙ Z  de⊙ Y₁)
                 f  _==_ {j} {de⊙ Y₁} (f (pt Z)) (pt Y₁))}
                (_⊙∘_ {k} {i} {j} {Z} {X} {Y₁} (⊙–> {i} {j} {X} {Y₁} ⊙e₁)
                (_⊙∘_ {k} {j} {i} {Z} {Y₁} {X} (⊙<– {i} {j} {X} {Y₁} ⊙e₁) k₁))
                k₁
      to-from ((f , idp) , f-ise) (k , k-pt) = ⊙λ=' (f.f-g  k) (↓-idf=cst-in' $ lemma k-pt)
        where
          module f = is-equiv {i} {j} f-ise
          lemma :  {y₀} (k-pt : y₀ == f (pt X))
             ⊙∘-pt f (⊙∘-pt f.g k-pt (f.g-f _)) idp == f.f-g y₀ ∙' k-pt
          lemma idp = ∙-unit-r _  f.adj _

      from-to : {Y = Y₁ : Ptd j} (⊙e₁ : _⊙≃_ {i} {j} X Y₁)
                (k₁ : _⊙→_ {k} {i} Z X) 
                _==_ {lmax i k}
                {Σ {lmax i k} {i} (de⊙ Z  de⊙ X)
                 f  _==_ {i} {de⊙ X} (f (pt Z)) (pt X))}
                (_⊙∘_ {k} {j} {i} {Z} {Y₁} {X} (⊙<– {i} {j} {X} {Y₁} ⊙e₁)
                (_⊙∘_ {k} {i} {j} {Z} {X} {Y₁} (⊙–> {i} {j} {X} {Y₁} ⊙e₁) k₁))
                k₁
      from-to ((f , idp) , f-ise) (k , idp) = ⊙λ=' (f.g-f  k) $ ↓-idf=cst-in' idp
        where module f = is-equiv {i} {j} f-ise

  post⊙∘-equiv : (Z ⊙→ X)  (Z ⊙→ Y)
  post⊙∘-equiv = _ , post⊙∘-is-equiv

  pre⊙∘-is-equiv : is-equiv  (k : Y ⊙→ Z)  k ⊙∘ ⊙–> ⊙e)
  pre⊙∘-is-equiv = is-eq (_⊙∘ ⊙–> ⊙e) (_⊙∘ ⊙<– ⊙e) (to-from ⊙e) (from-to ⊙e) where
    abstract
      to-from : {Z = Z₁ : Ptd k} (⊙e₁ : _⊙≃_ {i} {j} X Y)
                (k₁ : _⊙→_ {i} {k} X Z₁) 
                _==_ {lmax i k}
                {Σ {lmax i k} {k} (de⊙ X  de⊙ Z₁)
                 f  _==_ {k} {de⊙ Z₁} (f (pt X)) (pt Z₁))}
                (_⊙∘_ {i} {j} {k} {X} {Y} {Z₁}
                (_⊙∘_ {j} {i} {k} {Y} {X} {Z₁} k₁ (⊙<– {i} {j} {X} {Y} ⊙e₁))
                (⊙–> {i} {j} {X} {Y} ⊙e₁))
                k₁
      to-from ((f , idp) , f-ise) (k , idp) = ⊙λ=' (ap k  f.g-f) $ ↓-idf=cst-in' $ ∙-unit-r _
        where module f = is-equiv f-ise

      from-to : {Z = Z₁ : Ptd k} (⊙e₁ : _⊙≃_ {i} {j} X Y)
                (k₁ : _⊙→_ {j} {k} Y Z₁) 
                _==_ {lmax j k}
                {Σ {lmax j k} {k} (de⊙ Y  de⊙ Z₁)
                 f  _==_ {k} {de⊙ Z₁} (f (pt Y)) (pt Z₁))}
                (_⊙∘_ {j} {i} {k} {Y} {X} {Z₁}
                (_⊙∘_ {i} {j} {k} {X} {Y} {Z₁} k₁ (⊙–> {i} {j} {X} {Y} ⊙e₁))
                (⊙<– {i} {j} {X} {Y} ⊙e₁))
                k₁
      from-to ((f , idp) , f-ise) (k , idp) = ⊙λ=' (ap k  f.f-g) $ ↓-idf=cst-in' $
        ∙-unit-r _  ap-∘ k f (f.g-f (pt X))  ap (ap k) (f.adj (pt X))
        where module f = is-equiv f-ise

  pre⊙∘-equiv : (Y ⊙→ Z)  (X ⊙→ Z)
  pre⊙∘-equiv = _ , pre⊙∘-is-equiv

  pre⊙∘-hfib-contr : (g : X ⊙→ Z)  is-contr (Σ (Y ⊙→ Z)  k  (k ⊙∘ ⊙–> ⊙e) ⊙-crd∼ g))
  pre⊙∘-hfib-contr g =
    equiv-preserves-level (Σ-emap-r  _  ⊙-crd∼-==-≃)) {{equiv-is-contr-map (pre⊙∘-is-equiv) g}}

module _ {i j} {X : Ptd i} {Y : Ptd j} (⊙e : X ⊙≃ Y) where

  abstract
  
    linv⊙-unique : {f₁ f₂ : Y ⊙→ X}  (f₁ ⊙∘ ⊙–> ⊙e) ⊙-crd∼ ⊙idf X  (f₂ ⊙∘ ⊙–> ⊙e) ⊙-crd∼ ⊙idf X  f₁ == f₂
    linv⊙-unique {f₁} {f₂} p₁ p₂ = fst= (contr-has-all-paths {{pre⊙∘-hfib-contr ⊙e (⊙idf X)}} (f₁ , p₁) (f₂ , p₂))

    ⊙∘e-lunit : ⊙ide Y ⊙∘e ⊙e == ⊙e
    ⊙∘e-lunit = pair= (⊙λ= ((λ _  idp) , (ap-idf-idp (snd (fst ⊙e))))) prop-has-all-paths-↓

-- induction principle for ⊙≃

module _ {i} {X : Ptd i} where
 
  ⊙≃-contr-aux :
    is-contr
      (Σ (Σ (Type i)  A  de⊙ X  A))  (A , e)  Σ A  a₀  fst e (pt X) == a₀)))
  ⊙≃-contr-aux =
    equiv-preserves-level
      ((Σ-contr-red
        {P = λ (A , e)  Σ A  a₀  fst e (pt X) == a₀)} ≃-tot-contr)⁻¹)
      {{pathfrom-is-contr-instance}}

  abstract
    ⊙≃-contr : is-contr (Σ (Ptd i)  Y  X ⊙≃ Y))
    ⊙≃-contr = equiv-preserves-level lemma {{⊙≃-contr-aux}}
      where
        lemma :
          Σ (Σ (Type i)  A  de⊙ X  A))  (A , e)  Σ A  a₀  fst e (pt X) == a₀))
            
          Σ (Ptd i)  Y  X ⊙≃ Y)
        lemma =
          equiv
             ((A , e) , (a , p))  ⊙[ A , a ] , ≃-to-⊙≃ e p)
             (Y , ⊙e)  ((de⊙ Y) , (⊙≃-to-≃ ⊙e)) , ((pt Y) , (⊙–>-pt ⊙e)))
             (Y , ⊙e)  idp)
            λ ((A , e) , (a , p))  idp

  -- a version revealing the center of contraction
  ⊙≃-contr-exp : is-contr (Σ (Ptd i)  Y  X ⊙≃ Y))
  fst (has-level-apply ⊙≃-contr-exp) = X , (⊙ide X)
  snd (has-level-apply ⊙≃-contr-exp) = λ _  contr-has-all-paths {{⊙≃-contr}} _ _

  ⊙≃-ind :  {k} (P : (Y : Ptd i)  (X ⊙≃ Y  Type k))
     P X (⊙ide X)  {Y : Ptd i} (e : X ⊙≃ Y)  P Y e
  ⊙≃-ind P = ID-ind-map P ⊙≃-contr

  ⊙≃-ind-β :  {k} (P : (Y : Ptd i)  (X ⊙≃ Y  Type k))
     (r : P X (⊙ide X))  ⊙≃-ind P r (⊙ide X) == r
  ⊙≃-ind-β P = ID-ind-map-β P ⊙≃-contr

module _ {i} {X Y : Ptd i} where

  ⊙≃-to-== : X ⊙≃ Y  X == Y 
  ⊙≃-to-== = ⊙≃-ind {X = X}  Y _  X == Y) idp

  ⊙<–-coher⁻¹ : (⊙e : X ⊙≃ Y)  ⊙e-rev.lemma (⊙e ⊙⁻¹) (⊙e ⊙⁻¹) == snd (fst ⊙e)
  ⊙<–-coher⁻¹ = ⊙≃-ind {X = X}  Y ⊙e  ⊙e-rev.lemma (⊙e ⊙⁻¹) (⊙e ⊙⁻¹) == snd (fst ⊙e)) idp

  abstract
    ⊙<–-invl : (⊙e : X ⊙≃ Y)  ⊙<– (⊙e ⊙⁻¹) == fst ⊙e
    ⊙<–-invl ⊙e = ⊙-crd∼-to-== ((λ _  idp) , ⊙<–-coher⁻¹ ⊙e)

⊙≃-to-==-β :  {i} {X : Ptd i} {Y : Ptd i}  ⊙≃-to-== (⊙ide X) == idp
⊙≃-to-==-β {X = X} = ⊙≃-ind-β  Y _  X == Y) idp

⊙≃-from-== :  {i} {X : Ptd i} {Y : Ptd i}  X == Y  X ⊙≃ Y
⊙≃-from-== idp = ⊙ide _

⊙≃-ua :  {i} {X : Ptd i} {Y : Ptd i}  (X == Y)  (X ⊙≃ Y)
⊙≃-ua {X = X} = equiv ⊙≃-from-== ⊙≃-to-== rt1 rt2
  where
  
    rt1 :  {Y} (e : X ⊙≃ Y)  ⊙≃-from-== (⊙≃-to-== e) == e
    rt1 = ⊙≃-ind  Y e  ⊙≃-from-== (⊙≃-to-== e) == e) (ap (⊙≃-from-==) (⊙≃-to-==-β {Y = X}))

    rt2 :  {Y} (e : X == Y)  ⊙≃-to-== (⊙≃-from-== e) == e
    rt2 idp = ⊙≃-to-==-β {Y = X}

module _ {i j} {X : Ptd i} {Y : Ptd j} (⊙e₁ : X ⊙≃ Y)  where

  abstract
    ⊙<–-∘ : {Z : Ptd j} (⊙e₂ : Y ⊙≃ Z)  ⊙<– (⊙e₂ ⊙∘e ⊙e₁) == ⊙<– ⊙e₁ ⊙∘ ⊙<– ⊙e₂
    ⊙<–-∘ = ⊙≃-ind {X = Y}  Z ⊙e₂  ⊙<– (⊙e₂ ⊙∘e ⊙e₁) == ⊙<– ⊙e₁ ⊙∘ ⊙<– ⊙e₂) (ap ⊙<– (⊙∘e-lunit ⊙e₁))

{- Biinvertible maps -}

module _ {i j : ULevel} where

  infixr 80 _⊙-binv_
  _⊙-binv_ : (X : Ptd i) (Y : Ptd j)  Type (lmax i j)
  X ⊙-binv Y = [ f  X ⊙→ Y ] × [ g  Y ⊙→ X ] × (f ⊙∘ g == ⊙idf Y) × (g ⊙∘ f == ⊙idf X) 

  module _ {X : Ptd i} {Y : Ptd j} where

    ⊙-binv-to-⊙≃ : X ⊙-binv Y  X ⊙≃ Y
    fst (⊙-binv-to-⊙≃ (f , g , ri , li)) = f
    snd (⊙-binv-to-⊙≃ (f , g , ri , li)) = is-eq (fst f) (fst g) (fst (⊙app= ri)) (fst (⊙app= li))

{- Pointed maps out of bool -}

-- intuition : [f true] is fixed and the only changeable part is [f false].

⊙Bool→-to-idf :  {i} {X : Ptd i}
   ⊙Bool ⊙→ X  de⊙ X
⊙Bool→-to-idf (h , _) = h false

⊙Bool→-equiv-idf :  {i} (X : Ptd i)
   (⊙Bool ⊙→ X)  de⊙ X
⊙Bool→-equiv-idf {i} X = equiv ⊙Bool→-to-idf g f-g g-f
  where
  g : de⊙ X  ⊙Bool ⊙→ X
  g x = Bool-rec (pt X) x , idp

  abstract
    f-g :  x  ⊙Bool→-to-idf (g x) == x
    f-g x = idp

    g-f :  H  g (⊙Bool→-to-idf H) == H
    g-f (h , hpt) = pair=
      (λ= lemma)
      (↓-app=cst-in $
        idp
          =⟨ ! (!-inv-l hpt) 
        ! hpt  hpt
          =⟨ ! (app=-β lemma true) |in-ctx  w  w  hpt) 
        app= (λ= lemma) true  hpt
          =∎)
      where lemma :  b  fst (g (h false)) b == h b
            lemma true = ! hpt
            lemma false = idp

⊙Bool→-equiv-idf-nat :  {i j} {X : Ptd i} {Y : Ptd j} (F : X ⊙→ Y)
   CommSquareEquiv
      (F ⊙∘_)
      (fst F)
      ⊙Bool→-to-idf
      ⊙Bool→-to-idf
⊙Bool→-equiv-idf-nat F = (comm-sqr λ _  idp) ,
  snd (⊙Bool→-equiv-idf _) , snd (⊙Bool→-equiv-idf _)