Derivative.Basics.W

{-# OPTIONS -WnoUnsupportedIndexedMatch --safe #-}
module Derivative.Basics.W where

open import Derivative.Prelude
open import Derivative.Basics.Decidable
open import Derivative.Basics.Embedding
open import Derivative.Basics.Sigma
open import Derivative.Basics.Sum

open import Cubical.Foundations.Equiv.HalfAdjoint
open import Cubical.Foundations.Equiv.Dependent
open import Cubical.Foundations.Path
open import Cubical.Data.Sigma.Properties
open import Cubical.Relation.Nullary.Properties using (EquivPresDiscrete)
open import Cubical.Functions.Embedding
open import Cubical.Functions.FunExtEquiv

private
  variable
    ℓS ℓP ℓQ : Level

private
  module impl (S : Type ℓS) (P : S  Type ℓP) where
    data W : Type (ℓ-max ℓS ℓP) where
      sup : (s : S) (f : P s  W)  W

  module implᴰ (S : Type ℓS) (P : S  Type ℓP) (Q : S  Type ℓQ) where
    open impl S P

    data Wᴰ : W  Type (ℓ-max ℓQ (ℓ-of W)) where
      top : {s : S} {f : P s  W}  (q : Q s)  Wᴰ (sup s f)
      below : {s : S} {f : P s  W}  (p : P s)  (wᴰ : Wᴰ (f p))  Wᴰ (sup s f)

module _ {S : Type ℓS} {P : S  Type ℓP} where
  open impl S P

  W-elim :  {} {B : W  Type }
     (sup* : (s : S) (f : P s  W)  (sup* : (p : P s)  B (f p))  B (sup s f))
     (w : W)  B w
  W-elim {B} sup* (sup s f) = sup* s f λ p  W-elim {B = B} sup* (f p)

  W-elim2 :  {} {B : W  W  Type }
     (sup* : (s₀ s₁ : S) (f₀ : P s₀  W) (f₁ : P s₁  W)
       (sup* : (p₀ : P s₀)  (p₁ : P s₁)  B (f₀ p₀) (f₁ p₁))
       B (sup s₀ f₀) (sup s₁ f₁)
      )
     (w₀ w₁ : W)  B w₀ w₁
  W-elim2 {B} sup* (sup s₀ f₀) (sup s₁ f₁) = sup* s₀ s₁ f₀ f₁ λ p₀ p₁  W-elim2 {B = B} sup* (f₀ p₀) (f₁ p₁)

  W-out : W  (Σ[ s  S ] (P s  W))
  W-out (sup s f) = s , f

  W-shape : W  S
  W-shape = fst  W-out

  W-branch : (w : W)  P (W-shape w)  W
  W-branch = snd  W-out

  W-in : (Σ[ s  S ] (P s  W))  W
  W-in = uncurry sup

  W-in-equiv : (Σ[ s  S ] (P s  W))  W
  W-in-equiv = isoToEquiv iso module W-in-equiv where
    iso : Iso (Σ[ s  S ] (P s  W)) W
    iso .Iso.fun = W-in
    iso .Iso.inv = W-out
    iso .Iso.rightInv (sup s f) = refl
    iso .Iso.leftInv _ = refl

  W-rec :  {} {A : Type }
     (sup* : (Σ[ s  S ] (P s  A))  A)
     W  A
  W-rec {A} sup* (sup s f) = sup* (s , λ p  W-rec sup* (f p))

  W-rec-β :  {} {A : Type }
     (sup* : (Σ[ s  S ] (P s  A))  A)
     W-rec sup*  W-out  Σ-map-snd  _  W-rec sup* ∘_)  sup*
  W-rec-β sup* = funExt λ { (sup _ _ )  refl }

  W-out-equiv : W  (Σ[ s  S ] (P s  W))
  W-out-equiv = isoToEquiv (invIso W-in-equiv.iso)

  W-out-unique :  {} {A : Type } (f : (Σ[ s  S ] (P s  A))  A)  ∃![ f*  (W  A) ] f*  W-out  Σ-map-snd  s  f* ∘_)  f
  W-out-unique f .fst = W-rec f , W-rec-β f
  W-out-unique f .snd (f* , comm*) = ΣPathP (goal , goal-coh) module W-out-unique where
    goal-ext :  w  W-rec f w  f* w
    goal-ext (sup s x) = p  q
      module goal-ext where
        p = cong  -  f (s , - )) (funExt (goal-ext  x))
        q = sym (comm* ≡$ sup s x)

        filler = compPath-filler p q

    goal : W-rec f  f*
    goal = funExt goal-ext

    goal-coh-ext :  w  PathP  i  goal i w  (W-out  Σ-map-snd  _  (goal i) ∘_)  f) w) (W-rec-β f ≡$ w) (comm* ≡$ w)
    goal-coh-ext (sup s x) i j = goal-ext.filler s x (~ j) i

    goal-coh : PathP  i  goal i  W-out  Σ-map-snd  _  (goal i) ∘_)  f) (W-rec-β f) comm*
    goal-coh i j x = goal-coh-ext x i j

module _ {S : Type ℓS} {P : S  Type ℓP} where
  open impl
  WPath : (x y : W S P)  Type (ℓ-max ℓS ℓP)
  WPath (sup s₀ f₀) (sup s₁ f₁) = Σ (s₀  s₁) λ p  PathP  i  P (p i)  W S P) f₀ f₁

  ≡→WPath : (x y : W S P)  x  y  WPath x y
  ≡→WPath (sup s₀ f₀) (sup s₁ f₁) x≡y .fst = cong W-shape x≡y
  ≡→WPath (sup s₀ f₀) (sup s₁ f₁) x≡y .snd = cong W-branch x≡y

  WPath→≡ : (x y : W S P)  WPath x y  x  y
  WPath→≡ (sup s₀ f₀) (sup s₁ f₁) (s₀≡s₁ , f₀≡f₁) = cong₂ sup s₀≡s₁ f₀≡f₁

  WPath-linv-refl : (x : W S P)  WPath→≡ x x (≡→WPath x x refl)  refl
  WPath-linv-refl (sup s f) = refl

  WPath-linv : (x y : W S P) (p : x  y)  WPath→≡ _ _ (≡→WPath _ _ p)  p
  WPath-linv x y = J  y p  WPath→≡ _ _ (≡→WPath _ _ p)  p) $ WPath-linv-refl x

  WPath-rinv : (x y : W S P) (p : WPath x y)  ≡→WPath _ _ (WPath→≡ _ _ p)  p
  WPath-rinv (sup s₀ f₀) (sup s₁ f₁) _ = refl

  WPathIso : (x y : W S P)  Iso (x  y) (WPath x y)
  WPathIso x y .Iso.fun = ≡→WPath _ _
  WPathIso x y .Iso.inv = WPath→≡ _ _
  WPathIso x y .Iso.rightInv = WPath-rinv _ _
  WPathIso x y .Iso.leftInv = WPath-linv _ _

  WPath-≃ : (x y : W S P)  (x  y)  (WPath x y)
  WPath-≃ x y = isoToEquiv $ WPathIso x y

module _ (S : Type ℓS) (P : S  Type ℓP) (Q : S  Type ℓQ) where
  open impl S P
  open implᴰ S P Q

  module _ (s : S) (f : P s  W) where
    Wᴰ-out : Wᴰ (sup s f)  Q s  (Σ[ p  P s ] (Wᴰ (f p)))
    Wᴰ-out (top q) = inl q
    Wᴰ-out (below p wᴰ) = inr (p , wᴰ)

    Wᴰ-in : Q s  (Σ[ p  P s ] (Wᴰ (f p)))  Wᴰ (sup s f)
    Wᴰ-in (inl q) = top q
    Wᴰ-in (inr (p , wᴰ)) = below p wᴰ

    Wᴰ-out-equiv : Wᴰ (sup s f)  Q s  (Σ[ p  P s ] (Wᴰ (f p)))
    Wᴰ-out-equiv = isoToEquiv iso module Wᴰ-out-equiv where
      iso : Iso _ _
      iso .Iso.fun = Wᴰ-out
      iso .Iso.inv = Wᴰ-in
      iso .Iso.rightInv (inl _) = refl
      iso .Iso.rightInv (inr _) = refl
      iso .Iso.leftInv (top _) = refl
      iso .Iso.leftInv (below _ _) = refl

    Wᴰ-in-equiv : Q s  (Σ[ p  P s ] (Wᴰ (f p)))  Wᴰ (sup s f)
    Wᴰ-in-equiv = isoToEquiv (invIso Wᴰ-out-equiv.iso)

    isEquiv-Wᴰ-in : isEquiv Wᴰ-in
    isEquiv-Wᴰ-in = equivIsEquiv Wᴰ-in-equiv

  module _ (disc-P :  s  Discrete (P s)) (disc-Q :  s  Discrete (Q s)) where
    discrete-Wᴰ :  w  Discrete (Wᴰ w)
    discrete-Wᴰ (sup s f) = EquivPresDiscrete (Wᴰ-in-equiv s f) $
      discrete⊎
        (disc-Q s)
        (discreteΣ (disc-P s) (discrete-Wᴰ  f))

  Wᴰ-Path :  {w₀ w₁} (h : WPath w₀ w₁)  (x : Wᴰ w₀)  (y : Wᴰ w₁)  Type (ℓ-max ℓS (ℓ-max ℓP ℓQ))
  Wᴰ-Path (s₀≡s₁ , f₀≡f₁) (top q₀) (top q₁) = Lift {j = ℓ-max ℓS ℓP} $ PathP  i  Q (s₀≡s₁ i)) q₀ q₁
  Wᴰ-Path (s₀≡s₁ , f₀≡f₁) (top q₀) (below p₁ y) = 𝟘*
  Wᴰ-Path (s₀≡s₁ , f₀≡f₁) (below p₀ x) (top q₁) = 𝟘*
  Wᴰ-Path (s₀≡s₁ , f₀≡f₁) (below p₀ x) (below p₁ y)
    = Σ[ p₀≡p₁  PathP  i  P (s₀≡s₁ i)) p₀ p₁ ] PathP  i  Wᴰ (f₀≡f₁ i (p₀≡p₁ i))) x y

  Wᴰ-Path→≡ :  {w₀ w₁} {p : WPath w₀ w₁} {x : Wᴰ w₀} {y : Wᴰ w₁}  Wᴰ-Path p x y  PathP  i  Wᴰ (WPath→≡ _ _ p i)) x y
  Wᴰ-Path→≡ {x = top q₀}     {y = top q₁}     (lift q) i = top (q i)
  Wᴰ-Path→≡ {x = below p₀ x} {y = below p₁ y} (p₀≡p₁ , x≡y) i = below (p₀≡p₁ i) (x≡y i)

open impl public using (W ; sup)
open implᴰ public using (Wᴰ ; top ; below)

W-map :  {S S′ : Type ℓS} {P : S  Type ℓP} {P′ : S′  Type ℓP}
   (f : S  S′)
   (fᴰ :  s  P′ (f s)  P s)
   W S P  W S′ P′
W-map f fᴰ = W-elim λ s x map  sup (f s) (map  fᴰ s)

W-fiber-equiv :  {} {S : Type ℓS} {P : S  Type ℓP} {Y : Type }
   {f : W S P  Y}
   (y : Y)  fiber f y  (Σ[ s  S ] fiber (f  sup s) y)
W-fiber-equiv {S} {P} {Y} {f} y =
  Σ[ x  W S P ] f x  y
    ≃⟨ invEquiv $ Σ-cong-equiv-fst W-in-equiv 
  Σ[ (s , x)  Σ[ s  S ] (P s  W S P) ] f (sup s x)  y
    ≃⟨ Σ-assoc-≃ 
  Σ[ s  S ] Σ[ x  (P s  W S P) ] f (sup s x)  y
    ≃∎

isEmbedding→W-rec-fiber-equiv :  {} {S : Type ℓS} {P : S  Type ℓP} {A : Type }
   (sup* : (Σ[ s  S ] (P s  A))  A)
   isEmbedding sup*
   (s : S) (f : P s  W S P)
   fiber (W-rec sup*) (W-rec sup* (sup s f))  ((p : P s)  fiber (W-rec sup*) (W-rec sup* (f p)))
isEmbedding→W-rec-fiber-equiv {S} {P} {A} sup* is-emb-sup* s f =
  Σ[ x  W S P ] W-rec sup* x  sup* (s , W-rec sup*  f)
    ≃⟨ Σ-cong-equiv-snd  x  compPathlEquiv (sym $ W-rec-β sup* ≡$ x)) 
  Σ[ x  W S P ] sup* (W-out x .fst , _)  sup* (s , W-rec sup*  f)
    ≃⟨ Σ-cong-equiv-snd  x  invEquiv $ cong sup* , is-emb-sup* _ _) 
  Σ[ w  W S P ] (W-out w .fst , W-rec sup*  W-out w .snd)  (s , W-rec sup*  f)
    ≃⟨ invEquiv $ Σ-cong-equiv-fst $ W-in-equiv 
  Σ[ (s′ , f′)  (Σ[ s  S ] (P s  W S P)) ] (s′ , W-rec sup*  f′)  (s , W-rec sup*  f)
    ≃⟨ Σ-cong-equiv-snd  _  invEquiv ΣPathP≃PathPΣ) 
  Σ[ (s′ , f′)  (Σ[ s  S ] (P s  W S P)) ] Σ _ _
    ≃⟨ strictEquiv
       { ((s′ , f′) , s′≡s , f≡f′)  ((s′ , sym s′≡s) , (f′ , f≡f′)) })
       { ((s′ , s≡s′) , (f′ , f≡f′))  ((s′ , f′) , sym s≡s′ , f≡f′) })
    
  Σ[ (s′ , s≡s′)  singl s ] Σ[ f′  (P s′  W S P) ] PathP  i  P (s≡s′ (~ i))  A) (W-rec sup*  f′) (W-rec sup*  f)
    ≃⟨ Σ-contractFst (isContrSingl s) 
  Σ[ f′  (P s  W S P) ] (W-rec sup*  f′)  (W-rec sup*  f)
    ≃⟨ Σ-cong-equiv-snd  f′  invEquiv funExtEquiv) 
  Σ[ f′  (P s  W S P) ] ((p : P s)  W-rec sup* (f′ p)  W-rec sup* (f p))
    ≃⟨ invEquiv Σ-Π-≃ 
  ((p : P s)  fiber (W-rec sup*) (W-rec sup* (f p)))
    ≃∎

isEmbedding-W-rec :  {} {S : Type ℓS} {P : S  Type ℓP} {A : Type }
   (sup* : (Σ[ s  S ] (P s  A))  A)
   isEmbedding sup*
   isEmbedding (W-rec sup*)
isEmbedding-W-rec {S} {P} {A} sup* is-emb-sup* = hasPropFibersOfImage→isEmbedding prop-fibers where
  fiber-equiv :  s f  fiber (W-rec sup*) (W-rec sup* (sup s f))  ((p : P s)  fiber (W-rec sup*) (W-rec sup* (f p)))
  fiber-equiv = isEmbedding→W-rec-fiber-equiv sup* is-emb-sup*

  prop-fibers :  w  isProp (fiber (W-rec sup*) (W-rec sup* w))
  prop-fibers (sup s f) = isOfHLevelRespectEquiv 1 (invEquiv $ fiber-equiv s f) is-prop-fibers'
    where
      is-prop-fibers' : isProp (∀ p  fiber (W-rec sup*) (W-rec sup* (f p)))
      is-prop-fibers' = isPropΠ λ p  prop-fibers (f p)