Derivative.Basics.Sum

{-# OPTIONS --safe #-}
module Derivative.Basics.Sum where

open import Derivative.Prelude
open import Derivative.Basics.Embedding

open import Cubical.Data.Sigma
open import Cubical.Data.Sum public
open import Cubical.Functions.Embedding

private
  module Sum = Cubical.Data.Sum

private
  variable
     : Level
    A B : Type 
    C D : A  Type 

congInlEquiv : {x y : A}  (x  y)  (inl {B = B} x  inl y)
congInlEquiv .fst = cong inl
congInlEquiv .snd = Sum.isEmbedding-inl _ _

inlInj :  {x y : A}  inl {B = B} x  inl y  x  y
inlInj = isEmbedding→Inj Sum.isEmbedding-inl _ _

inrInj :  {x y : B}  inr {A = A} x  inr y  x  y
inrInj = isEmbedding→Inj Sum.isEmbedding-inr _ _

inr≢inl :  {x : A} {y : B}  inr x  inl y
inr≢inl p = Sum.⊎Path.encode _ _ p .lower

Σ-⊎-fst-≃ : {E : A  B  Type }  (Σ (A  B) E)  (Σ A (E  inl)  Σ B (E  inr))
Σ-⊎-fst-≃ = Sum.Σ⊎≃

Σ-⊎-snd-Iso : Iso (Σ[ a  A ] C a  D a) (Σ A C  Σ A D)
Σ-⊎-snd-Iso .Iso.fun = uncurry λ a  Sum.rec  b  inl (a , b))  c  inr (a , c))
Σ-⊎-snd-Iso .Iso.inv = Sum.rec  (a , b)  a , inl b)  (a , c)  a , inr c)
Σ-⊎-snd-Iso .Iso.rightInv = Sum.elim  _  refl)  _  refl)
Σ-⊎-snd-Iso .Iso.leftInv = uncurry λ a  Sum.elim  b  refl)  c  refl)

Σ-⊎-snd-≃ : (Σ[ a  A ] C a  D a)  (Σ A C  Σ A D)
Σ-⊎-snd-≃ = isoToEquiv Σ-⊎-snd-Iso

⊎-map-left :  {C : Type }  (f : A  B)  (A  C)  (B  C)
⊎-map-left f (inl a) = inl (f a)
⊎-map-left f (inr b) = inr b

⊎-left-Iso :  {C : Type }  Iso A B  Iso (A  C) (B  C)
⊎-left-Iso iso .Iso.fun = ⊎-map-left (iso .Iso.fun)
⊎-left-Iso iso .Iso.inv = ⊎-map-left (iso .Iso.inv)
⊎-left-Iso iso .Iso.rightInv (inl a) = cong inl (iso .Iso.rightInv a)
⊎-left-Iso iso .Iso.rightInv (inr c) = refl
⊎-left-Iso iso .Iso.leftInv (inl b) = cong inl (iso .Iso.leftInv b)
⊎-left-Iso iso .Iso.leftInv (inr c) = refl

⊎-left-≃ :  {C : Type }  (e : A  B)  (A  C)  (B  C)
⊎-left-≃ e = isoToEquiv (⊎-left-Iso (equivToIso e))

⊎-map-right :  {C : Type }  (f : B  C)  (A  B)  (A  C)
⊎-map-right f (inl a) = inl a
⊎-map-right f (inr b) = inr (f b)

⊎-map-right-cong :  {C : Type }
   {f g : B  C}
   (f  g)
   ⊎-map-right {A = A} f  ⊎-map-right g
⊎-map-right-cong p i (inl a) = inl a
⊎-map-right-cong p i (inr b) = inr (p i b)

⊎-right-Iso :  {C : Type }  Iso B C  Iso (A  B) (A  C)
⊎-right-Iso iso .Iso.fun = ⊎-map-right (iso .Iso.fun)
⊎-right-Iso iso .Iso.inv = ⊎-map-right (iso .Iso.inv)
⊎-right-Iso iso .Iso.rightInv (inl a) = refl
⊎-right-Iso iso .Iso.rightInv (inr b) = cong inr (iso .Iso.rightInv b)
⊎-right-Iso iso .Iso.leftInv (inl a) = refl
⊎-right-Iso iso .Iso.leftInv (inr c) = cong inr (iso .Iso.leftInv c)

⊎-right-≃ :  {C : Type }  (e : B  C)  (A  B)  (A  C)
⊎-right-≃ e = isoToEquiv (⊎-right-Iso (equivToIso e))

isEquiv→isEquiv-⊎-map-right :  {C : Type } {f : B  C}
   isEquiv f
   isEquiv (⊎-map-right {A = A} f)
isEquiv→isEquiv-⊎-map-right {C} {f} is-equiv-f = equivIsEquiv (⊎-right-≃ (f , is-equiv-f))

⊎-empty-left-Iso : (¬ A)  Iso B (A  B)
⊎-empty-left-Iso ¬A .Iso.fun = inr
⊎-empty-left-Iso ¬A .Iso.inv (inl a) = ex-falso $ ¬A a
⊎-empty-left-Iso ¬A .Iso.inv (inr b) = b
⊎-empty-left-Iso ¬A .Iso.rightInv (inl a) = ex-falso $ ¬A a
⊎-empty-left-Iso ¬A .Iso.rightInv (inr b) = refl
⊎-empty-left-Iso ¬A .Iso.leftInv b = refl

⊎-empty-left : (¬ A)  B  (A  B)
⊎-empty-left = isoToEquiv  ⊎-empty-left-Iso

⊎-empty-right : (¬ B)  A  (A  B)
⊎-empty-right ¬B .fst = inl
⊎-empty-right ¬B .snd .equiv-proof (inl a) = isOfHLevelRespectEquiv 0 fiber-equiv (isContrSingl a) where
  fiber-equiv : singl a  fiber inl (inl a)
  fiber-equiv = Σ-cong-equiv-snd λ a′  symEquiv ∙ₑ congInlEquiv
⊎-empty-right ¬B .snd .equiv-proof (inr b) = ex-falso (¬B b)

⊎-fiber-≃ : {C : Type } {f : A  B  C}   y  fiber f y  (fiber (f  inl) y)  (fiber (f  inr) y)
⊎-fiber-≃ y = Σ-⊎-fst-≃

⊎-map-right-fiber-inr-equiv :  {C : Type }  (f : B  C)
   (c : C)  fiber (⊎-map-right {A = A} f) (inr c)  fiber f c
⊎-map-right-fiber-inr-equiv {B} {A} {C} f c =
  Σ[ x  A  B ] ⊎-map-right f x  inr c
    ≃⟨ ⊎-fiber-≃ (inr c) 
  (Σ[ a  A ] inl a  inr c)  (fiber (f  inr) (inr c))
    ≃⟨ invEquiv $ ⊎-empty-left $ uncurry  _  inr≢inl  sym) 
  fiber (f  inr) (inr c)
    ≃⟨ postCompEmbeddingFiberEquiv f inr isEmbedding-inr c 
  fiber f c
    ≃∎

⊎-map-right-fiber-inl-equiv :  {C : Type }
   (f : B  C)
   (a : A)
   fiber (⊎-map-right {A = A} f) (inl a)  singl a
⊎-map-right-fiber-inl-equiv {B} {A} f a =
  Σ[ x  A  B ] ⊎-map-right f x  inl a
    ≃⟨ ⊎-fiber-≃ (inl a) 
  (Σ[ a′  A ] inl a′  inl a)  (fiber (f  inr) (inl a))
    ≃⟨ invEquiv $ ⊎-empty-right $ uncurry  _  inr≢inl) 
  (Σ[ a′  A ] inl a′  inl a)
    ≃⟨ Σ-cong-equiv-snd  a′  invEquiv $ cong inl , isEmbedding-inl a′ a) 
  (Σ[ a′  A ] a′  a)
    ≃⟨ Σ-cong-equiv-snd  a′  symEquiv) 
  singl a
    ≃∎

isEquiv-⊎-map-right→isEquiv :  {C : Type }
   (f : B  C)
   isEquiv (⊎-map-right {A = A} f)
   isEquiv f
isEquiv-⊎-map-right→isEquiv {A} {C} f is-equiv-map .equiv-proof = goal where
  goal : (c : C)  isContr (fiber f c)
  goal c = isOfHLevelRespectEquiv 0 (⊎-map-right-fiber-inr-equiv f c) (is-equiv-map .equiv-proof (inr c))

isEmbedding-⊎-map-right :  {C : Type }
   (f : B  C)
   isEmbedding f
   isEmbedding (⊎-map-right {A = A} f)
isEmbedding-⊎-map-right {A} f is-embedding-f = hasPropFibers→isEmbedding prop-fibers
  where
    prop-fibers :  y  isProp (fiber (⊎-map-right {A = A} f) y)
    prop-fibers (inl a) = isOfHLevelRespectEquiv 1 (invEquiv $ ⊎-map-right-fiber-inl-equiv f a)
      $ isContr→isProp $ isContrSingl a
    prop-fibers (inr c) = isOfHLevelRespectEquiv 1 (invEquiv $ ⊎-map-right-fiber-inr-equiv f c)
      $ isEmbedding→hasPropFibers is-embedding-f c