Derivative.Container

{-# OPTIONS --safe #-}
module Derivative.Container where

open import Derivative.Prelude
import      Derivative.Basics.Maybe as Maybe
open import Derivative.Basics.Sum as Sum using (_⊎_)

open import Cubical.Foundations.Transport using (substEquiv)
open import Cubical.Reflection.RecordEquiv
open import Cubical.Data.Sigma.Base

record Container (ℓS ℓP : Level) : Type (ℓ-suc (ℓ-max ℓS ℓP)) where
  -- no-eta-equality
  constructor _◁_
  field
    Shape : Type ℓS
    Pos : Shape  Type ℓP

private
  variable
    ℓS ℓP  : Level

Container-syntax : (S : Type ℓS)  (P : S  Type ℓP)  Container ℓS ℓP
Container-syntax = _◁_

syntax Container-syntax S  s  P) = [ s  S ]◁ P

open Container

isTruncatedContainer : (n k : HLevel)  Container ℓS ℓP  Type _
isTruncatedContainer n k (S  P) = isOfHLevel n S ×  s  isOfHLevel k (P s)

isSetContainer : Container ℓS ℓP  Type _
isSetContainer = isTruncatedContainer 2 2

TruncatedContainer : (n k : HLevel) (ℓS ℓP : Level)  Type (ℓ-suc (ℓ-max ℓS ℓP))
TruncatedContainer n k ℓS ℓP = Σ (Container ℓS ℓP) (isTruncatedContainer n k)

SetContainer : (ℓS ℓP : Level)  Type (ℓ-suc (ℓ-max ℓS ℓP))
SetContainer = TruncatedContainer 2 2

_⊗_ : (F G : Container ℓS ℓP)  Container _ _
(F  G) .Shape = F .Shape × G .Shape
(F  G) .Pos x = F .Pos (x .fst)  G .Pos (x .snd)
infix 11 _⊗_

Id : Container ℓS ℓP
Id .Shape = 𝟙*
Id .Pos = const 𝟙*

_⊗Id : Container ℓS ℓP  Container ℓS ℓP
F ⊗Id = F  Id

_⊕_ : (F G : Container ℓS ℓP)  Container _ _
(F  G) .Shape = F .Shape  G .Shape
(F  G) .Pos (Sum.inl s) = F .Pos s
(F  G) .Pos (Sum.inr t) = G .Pos t
infix 10 _⊕_

Const : (S : Type )  Container  
Const S .Shape = S
Const S .Pos _ = 𝟘*

One : ( : Level)  Container  
One  = Const 𝟙*

record Cart {ℓS ℓT ℓP ℓQ} (F : Container ℓS ℓP) (G : Container ℓT ℓQ) : Type (ℓ-max (ℓ-max ℓS ℓP) (ℓ-max ℓT ℓQ)) where
  constructor [_◁_]
  field
    shape : F .Shape  G .Shape
    pos :  s  G .Pos (shape s)  F .Pos s

open Cart

unquoteDecl Cart-Σ-Iso = declareRecordIsoΣ Cart-Σ-Iso (quote Cart)

Cart-Σ-equiv :  {ℓS ℓT ℓP ℓQ} {F : Container ℓS ℓP} {G : Container ℓT ℓQ}
   Cart F G  (Σ[ fₛₕ  (F .Shape  G .Shape) ]  s  G .Pos (fₛₕ s)  F .Pos s)
Cart-Σ-equiv = isoToEquiv Cart-Σ-Iso

Cart≡ : {F G : Container ℓS ℓP}
   {f g : Cart F G}
   (p : f .shape  g .shape)
   (q : PathP  i   s  G .Pos (p i s)  F .Pos s) (f .pos) (g .pos))
   f  g
Cart≡ p q i .shape = p i
Cart≡ p q i .pos = q i

Cart≡Equiv : {F G : Container ℓS ℓP}
   (f g : Cart F G)
   (Σ[ p  f .shape  g .shape ] (PathP  i   s  G .Pos (p i s)  F .Pos s) (f .pos) (g .pos)))  (f  g)
Cart≡Equiv f g = strictIsoToEquiv iso module Cart≡Equiv where
  iso : Iso _ _
  iso .Iso.fun = uncurry Cart≡
  iso .Iso.inv p .fst = cong shape p
  iso .Iso.inv p .snd = cong pos p
  iso .Iso.rightInv _ = refl
  iso .Iso.leftInv _ = refl

_⋆_ :  {F G H : Container ℓS ℓP}  Cart F G  Cart G H  Cart F H
(f  g) .shape = g .shape  f .shape
(f  g) .pos s = g .pos (f .shape s) ∙ₑ f .pos s
-- {-# INJECTIVE_FOR_INFERENCE _⋆_ #-}

id : (F : Container ℓS ℓP)  Cart F F
id F .shape s = s
id F .pos s = idEquiv _

TruncatedCart : {n k : HLevel}  (F G : TruncatedContainer n k ℓS ℓP)  Type _
TruncatedCart F G = Cart (F .fst) (G .fst)
{-# INJECTIVE_FOR_INFERENCE TruncatedCart #-}

SetCart : (F G : TruncatedContainer 2 2 ℓS ℓP)  Type _
SetCart = TruncatedCart {n = 2} {k = 2}

isOfHLevelCart : (n : HLevel)  {F G : TruncatedContainer n n ℓS ℓP}  isOfHLevel n (TruncatedCart F G)
isOfHLevelCart n {F = _ , _ , trunc-pos-F} {G = _ , trunc-shape-G , trunc-pos-G} = isOfHLevelRetractFromIso n Cart-Σ-Iso
  $ isOfHLevelΣ n
    (isOfHLevelΠ n λ _  trunc-shape-G)
    λ f  isOfHLevelΠ n λ s  isOfHLevel≃ n (trunc-pos-G (f s)) (trunc-pos-F s)

module CartReasoning where
  private
    variable
      F G H : Container ℓS ℓP

  _⊸⟨_⟩_ : (F : Container ℓS ℓP) {G H : Container ℓS ℓP}  Cart F G  Cart G H  Cart F H
  _⊸⟨_⟩_ F {G} {H} f g = _⋆_ {F = F} {G = G} {H = H} f g

  _⊸∎ : (F : Container ℓS ℓP)  Cart F F
  F ⊸∎ = id F
  {-# INLINE _⊸∎ #-}

  infixr 0 _⊸⟨_⟩_
  infix 1 _⊸∎

open CartReasoning public

[_]⊗Id : {F G : Container ℓS ℓP}  Cart F G  Cart (F ⊗Id) (G ⊗Id)
[_]⊗Id {F} {G} f .shape s = f .shape (s .fst) , _
[_]⊗Id {F} {G} f .pos s = Sum.⊎-left-≃ (f .pos (s .fst))

record Equiv (F G : Container ℓS ℓP) : Type (ℓ-max ℓS ℓP) where
  constructor [_◁≃_]
  field
    shape : F .Shape  G .Shape
    pos :  s  G .Pos (equivFun shape s)  F .Pos s

Equiv→Cart : {F G : Container ℓS ℓP}  Equiv F G  Cart F G
Equiv→Cart [ shape ◁≃ pos ] .shape = equivFun shape
Equiv→Cart [ shape ◁≃ pos ] .pos = pos

_⋆ₑ_ :  {F G H : Container ℓS ℓP}  Equiv F G  Equiv G H  Equiv F H
(f ⋆ₑ g) .Equiv.shape = f .Equiv.shape ∙ₑ g .Equiv.shape
(f ⋆ₑ g) .Equiv.pos s = g .Equiv.pos (equivFun (f .Equiv.shape) s) ∙ₑ f .Equiv.pos s

idₑ : (F : Container ℓS ℓP)  Equiv F F
idₑ F .Equiv.shape = idEquiv _
idₑ F .Equiv.pos _ = idEquiv _

-- TODO: Rename to Equiv-shape and Equiv-pos
Equiv-fst :  {S S′ : Type ℓS} {P : S′  Type ℓP}
   (e : S  S′)
   Equiv (S  (P  equivFun e)) (S′  P)
Equiv-fst {S} {P} e .Equiv.shape = e
Equiv-fst {S} {P} e .Equiv.pos s = idEquiv (P (equivFun e s))

Equiv-snd :  {S : Type ℓS} {P P′ : S  Type ℓP}
   (e :  s  P′ s  P s)
   Equiv (S  P) (S  P′)
Equiv-snd {S} e .Equiv.shape = idEquiv S
Equiv-snd {S} e .Equiv.pos = e

Equiv-inv : {F G : Container ℓS }  Equiv F G  Equiv G F
Equiv-inv {F} {G} [ shape ◁≃ pos ] .Equiv.shape = invEquiv shape
Equiv-inv {F} {G} [ shape ◁≃ pos ] .Equiv.pos t = invEquiv $ substEquiv (G .Pos) (sym (secEq shape t)) ∙ₑ pos (invEq shape t)

module EquivReasoning where
  private
    variable
      F G H : Container ℓS ℓP

  _⊸≃⟨_⟩_ : (F : Container ℓS ℓP)  Equiv F G  Equiv G H  Equiv F H
  _⊸≃⟨_⟩_ {G} {H} F f g = _⋆ₑ_ {F = F} {G = G} {H = H} f g

  _⊸≃∎ : (F : Container ℓS ℓP)  Equiv F F
  F ⊸≃∎ = idₑ F
  {-# INLINE _⊸≃∎ #-}

  _⊸≃⟨⟩_ : (F : Container ℓS ℓP)  Equiv F G  Equiv F G
  F ⊸≃⟨⟩ e = e

  infixr 0 _⊸≃⟨_⟩_
  infixr 0 _⊸≃⟨⟩_
  infix 1 _⊸≃∎

open EquivReasoning public

_[_] : (F G : Container  )  Container  
(F [ G ]) .Shape = Σ[ s  F .Shape ] (F .Pos s  G .Shape)
(F [ G ]) .Pos (s , f) = Σ[ p  F .Pos s ] G .Pos (f p)