{-# OPTIONS --rewriting #-}

open import Agda.Primitive

module Lib where

  ℓ₀ = lzero
  ℓ₁ = lsuc ℓ₀
  ℓ₂ = lsuc ℓ₁
  ℓ₃ = lsuc ℓ₂

  -- FIXME rename transport/coe so they look less HoTT-like

  _o_ : ∀ {l1 l2 l3} {A : Set l1} {B : Set l2} {C : Set l3} → (B → C) → (A → B) → A → C
  g o f = \ x → g (f x)
  infixr 10 _o_

  data _==_ {l : Level} {A : Set l} (M : A) : A → Set l where
    id : M == M

  {-# BUILTIN REWRITE _==_ #-}
  {-# BUILTIN EQUALITY _==_ #-}

  postulate
    λ=  : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {f g : (x : A) -> B x} -> ((x : A) -> (f x) == (g x)) -> f == g
    λ=i  : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {f g : {x : A} -> B x} -> ((x : A) -> (f {x}) == (g {x})) -> (\ {x} → f {x}) == (\ {x} → g {x})
    λ=inf  : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {f g : {{x : A}} -> B x} -> ((x : A) -> (f {{x}}) == (g {{x}})) -> (\ {{x}} → f {{x}}) == (\ {{x}} → g {{x}})

  ! : ∀ {l} {A : Set l} {M N : A} → M == N → N == M
  ! id = id

  _∘_  : ∀ {l} {A : Set l} {M N P : A} → N == P → M == N → M == P
  β ∘ id = β

  _=〈_〉_ : ∀ {l} {A : Set l} (x : A) {y z : A} → x == y → y == z → x == z
  _ =〈 p1 〉 p2 = (p2 ∘ p1)
 
  _∎ : ∀ {l} {A : Set l} (x : A) → x == x
  _∎ _ = id

  infix  2 _∎
  infixr 2 _=〈_〉_ 

  infixr 10 _∘_ 

  transport : ∀ {l1 l2 : Level} {A : Set l1} (C : A →  Set l2) {M N : A} 
              (P : M == N) → C M → C N
  transport C id x = x

  transport! : ∀ {l1 l2 : Level} {A : Set l1} (C : A →  Set l2) {M N : A} 
              (P : M == N) → C N → C M
  transport! C p x = transport C (! p) x

  coe : ∀ {l1 : Level} {A B : Set l1} (P : A == B) → A → B
  coe p x = transport (\ X → X) p x

  coe! : ∀ {l1 : Level} {A B : Set l1} (P : A == B) → B → A
  coe! p x = transport! (\ X → X) p x

  ap :  {l1 l2 : Level} {A : Set l1} {B : Set l2} {M N : A}
       (f : A → B) → M == N → (f M) == (f N)
  ap f id = id

  ap! :  {l1 l2 : Level} {A : Set l1} {B : Set l2} {M N : A}
       (f : A → B) → M == N → (f N) == (f M)
  ap! f p = ap f (! p)

  ap2 : ∀ {l1 l2 l3} {A : Set l1} {B : Set l2} {C : Set l3}
          {M N : A} {M' N' : B} (f : A -> B -> C) -> M == N -> M' == N' 
          -> (f M M') == (f N N')
  ap2 f id id = id

{-
  data Either {l1 l2 : Level} (A : Set l1) (B : Set l2) : Set (l1 ⊔ l2) where
    Inl : A → Either A B
    Inr : B → Either A B
-}

  record Σe {l1 l2} (A : Set l1) (B : A -> Set l2) : Set (l1 ⊔ l2) where
     constructor _,_
     field
       fst : A
       snd : B fst
  open Σe public
  
  Σ : ∀ {l1 l2} {A : Set l1} -> (B : A -> Set l2) -> Set (l1 ⊔ l2)
  Σ {_}{_}{A} B = Σe A B
  
  infixr 0 _,_
  
  syntax Σe A (\ x  -> B) = Σ[ x ∶ A ] B

  record Unit{l : Level} : Set l where
    constructor <> 

  _×_ : ∀{ l1 l2} → Set l1 -> Set l2 -> Set (l1 ⊔ l2)
  a × b = Σ (\ (_ : a) -> b)

  uip : ∀ {l} {A : Set l} {x y : A} {p q : x == y} → p == q
  uip {p = id} {q = id} = id

  data ⊥ {l : Level} : Set l where 
  
  abort : ∀ {l1 l2 : Level} {A : Set l2} → ⊥{l1} → A
  abort () 

  transport-ap-assoc' : ∀ {l1 l2 l3} {A : Set l1} {B : Set l2} (C : B → Set l3) (f : A → B) {M N : A} (α : M == N) 
                     → (transport (\ x -> C (f x)) α) == (transport C (ap f α))
  transport-ap-assoc' C f id = id 

  apd  : ∀ {l1 l2} {B : Set l1} {E : B → Set l2} {b₁ b₂ : B} 
         (f : (x : B) → E x) (β : b₁ == b₂) 
      → transport E β (f b₁) == (f b₂) 
  apd f id = id 

  apd!  : ∀ {l1 l2} {B : Set l1} {E : B → Set l2} {b₁ b₂ : B} 
         (f : (x : B) → E x) (β : b₁ == b₂) 
      → (f b₁) == transport E (! β) (f b₂) 
  apd! f id = id 

  ap= : ∀ {l1 l2} {A : Set l1} {B : A → Set l2} {f g : (x : A) → B x} 
        → f == g → {x : A} → (f x) == (g x)
  ap= α {x} = ap (\ f → f x) α

  ×= :  ∀ {l1 l2} {A : Set l1} {B : Set l2} {p q : A × B} -> (α : (fst p) == (fst q)) -> (snd p) == (snd q) -> p == q
  ×= id id = id

  pair= : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {p q : Σ B} -> (α : (fst p) == (fst q)) -> (transport B α (snd p)) == (snd q) -> p == q
  pair= {p = x , y} {q = .x , .y} id id = id

  pair=! : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {p q : Σ B} -> (α : (fst p) == (fst q)) -> (snd p) == transport B (! α) (snd q) -> p == q
  pair=! {p = x , y} {q = .x , .y} id id = id

  transport-∘ : {l1 l2 : Level} {A : Set l1} (C : A → Set l2) {M N P : A} (β : N == P) (α : M == N)
           →  (transport C (β ∘ α)) == (\ x → transport C β (transport C α x))
  transport-∘ _ id id = id

  transport-Π : ∀ {l l1 l2} {Γ : Set l} (A : Γ -> Set l1) (B : (γ : Γ) -> A γ -> Set l2)
            {θ1 θ2 : Γ} (δ : θ1 == θ2) (f : (x : A θ1) -> B θ1 x) 
         -> transport (\ γ -> (x : A γ) -> B γ x) δ f == 
            (\ x -> transport (\ (p : Σ \ (γ : Γ) -> A γ) -> B (fst p) (snd p))
                          (pair=! δ id)
                          (f (transport A (! δ) x)))
  transport-Π _ _ id f = id

  transport-→-post' : ∀ {l l1 l2} {Γ : Set l} (A : Set l1) (B : (γ : Γ) -> Set l2)
            {θ1 θ2 : Γ} (δ : θ1 == θ2) (f : A -> B θ1) (x : A) 
         -> (transport (\ (x : Γ) -> A -> B x) δ f) x == transport B δ (f  x)
  transport-→-post' _ _ id f x = id

  transport-→-pre' : ∀ {l1 l2 l3} {Γ : Set l1} {B : Set l2} (A : Γ -> Set l3) {θ1 θ2 : Γ} 
                  (δ : θ1 == θ2) (f : (x : A θ1) → B) 
     →  (transport (\ γ → (A γ) → B) δ f)  == (\ x -> f (transport (\ γ -> A γ) (! δ) x))
  transport-→-pre' _ id f = id 

  transport-→-pre-inv : ∀ {l1 l2 l3} {Γ : Set l1} {B : Set l2} (A : Γ -> Set l3) {θ1 θ2 : Γ} 
                  (δ : θ1 == θ2) (f : (x : A θ2) → B) 
     →  (transport (\ γ → (A γ) → B) (! δ) f)  == (\ x -> f (transport (\ γ -> A γ) δ x))
  transport-→-pre-inv _ id f = id 

  fst-transport-Σ : ∀ {l1 l2 l3} {C : Set l1} {A : Set l2} {B : C → A → Set l3} {c c' : C}
                  → (p : c == c')
                  → (ab : Σ \ x → B c x)
                  → fst (transport (\ h → Σ \ (x : A) → B h x) p ab) == fst ab
  fst-transport-Σ id ab = id

  fst-transport-Σ' : ∀ {l1 l2 l3} {C : Set l1} {A : C → Set l2} {B : (c : C) → A c → Set l3} {c c' : C}
                  → (p : c == c')
                  → (ab : Σ \ x → B c x)
                  → fst (transport (\ h → Σ \ (x : A h) → B h x) p ab) == transport A p (fst ab)
  fst-transport-Σ' id ab = id

  snd-transport-×' : ∀ {l1 l2 l3} {C : Set l1} {A : C → Set l2} {B : C → Set l3} {c c' : C}
                  → (p : c == c')
                  → (ab : A c × B c)
                  → snd (transport (\ h →  A h × B h) p ab) == transport B p (snd ab)
  snd-transport-×' id ab = id

  move-transport-right : ∀ {l1 l2} {A : Set l1} {M M' : A} (B : A → Set l2)
                          (α : M == M') {b : B M} {b' : B M'}
                       -> (transport B α b == b')
                       → (b == transport B (! α) b')
  move-transport-right B id p = p

  move-transport-right! : ∀ {l1 l2} {A : Set l1} {M M' : A} (B : A → Set l2)
                          (α : M' == M) {b : B M} {b' : B M'}
                       -> (transport B (! α) b == b')
                       → (b == transport B α b')
  move-transport-right! B id p = p

  move-transport-left! : ∀ {l1 l2} {A : Set l1} {M M' : A} (B : A → Set l2)
                          (α : M' == M) {b : B M} {b' : B M'}
                       -> (b == transport B α b')
                       → (transport B (! α) b == b')
  move-transport-left! B id p = p

  move-transport-left : ∀ {l1 l2} {A : Set l1} {M M' : A} (B : A → Set l2)
                          (α : M == M') {b : B M} {b' : B M'}
                       → (b == transport B (! α) b')
                       → (transport B α b == b')
  move-transport-left B id p = p

  transport-inv : {l1 l2 : Level} {A : Set l1} (B : A -> Set l2) {M N : A} (α : M == N) -> (\y -> transport B (! α) (transport B α y)) == (\ x -> x)
  transport-inv _ id = id

  transport-inv-2 : {l1 l2 : Level} {A : Set l1} (B : A -> Set l2) {M N : A} (α : M == N) -> (\y -> transport B α (transport B (! α) y)) == (\ x -> x)
  transport-inv-2 _ id = id

  transport-→-post : ∀ {l1 l2} {C : Set l1} {A : Set l2} {B : Set l1} (δ : B == C) (f : A -> B) 
         -> transport (\ X -> A -> X) δ f == (transport (\ X -> X) δ o f)
  transport-→-post id f = id 

  transport-constant : ∀ {l1 l2} {A : Set l1} {C : Set l2} {M N : A} -> (p : M == N) -> (transport (\ _ -> C) p) == (\ x -> x)
  transport-constant id = id 

  transport-natural-trans : {l1 l2 l3 : Level} {A : Set l1} {B : A → Set l2} {C : A → Set l3}
                   → (f : (x : A) → B x → C x)
                   → {x y : A} (p : x == y) (b : B x)
                   → f y (transport B p b) == transport (\ x → C x) p (f x b)
  transport-natural-trans f id b = id


  -- there aren't used much, but there was one spot that was unpalatable without using pathovers

  data _=h_ {l1 : Level} {A : Set l1} (M : A) : {B : Set l1} → B → Set (l1) where
    hid : M =h M

  postulate
    λ=o  : ∀ {l1 l2} {A A' : Set l1} {B : A -> Set l2} {B' : A' -> Set l2}
             {f : (x : A) -> B x} {g : (x : A') -> B' x}
          -> ((x : A) (y : A') -> x =h y → (f x) =h (g y))
          -> f =h g

    λ=o1 : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {B' : A -> Set l2}
             {f : (x : A) -> B x} {g : (x : A) -> B' x}
          -> ((x : A) → (f x) =h (g x))
          -> f =h g

  transport-=h : ∀ {l1 l2 : Level} {A : Set l1} (C : A →  Set l2) {M N : A} (P : M == N) {c : C M}
               → transport C P c =h c
  transport-=h C id = hid

  _∘h_  : ∀ {l} {A B C : Set l} {M : A} {N : B} {P : C} → N =h P → M =h N → M =h P
  β ∘h hid = β
  infixr 10 _∘h_ 

  !h : ∀ {l} {A B : Set l} {M : A} {N : B} → M =h N → N =h M
  !h hid = hid

  het-to-hom : {l : Level} {A : Set l} {M N : A} → M =h N → M == N
  het-to-hom hid = id

  hom-to-het : ∀ {l1 : Level} {A : Set l1} {M N : A}
               → M == N
               → M =h N
  hom-to-het id = hid

  hom-to-het' : ∀ {l1 l2 : Level} {A : Set l1} (C : A →  Set l2) {M N : A} (P : M == N) {c : C M} {d : C N}
               → transport C P c == d
               → c =h d
  hom-to-het' C id id = hid

  apdo  : ∀ {l1 l2} {B : Set l1} {E : B → Set l2} {b₁ b₂ : B} 
         (f : (x : B) → E x) (β : b₁ == b₂) 
      → (f b₁) =h (f b₂) 
  apdo f id = hid 

  apdo2 :  {l1 l2 l3 : Level} {A : Set l1} {B : A → Set l2} {C : (x : A) → B x → Set l3} 
          {a a' : A} {b : B a} {b' : B a'} 
       → (f : (a : A) → (b : B a) → C a b)
       → a == a' → b =h b' → (f a b) =h (f a' b')
  apdo2 f id hid = hid

  apdo3 :  {l1 l2 l3 l4 : Level} {A : Set l1} {B : A → Set l2} {C : (x : A) → B x → Set l3} {D : (x : A) → (b : B x) (c : C x b) → Set l4}
          {a a' : A} {b : B a} {b' : B a'} {c : C a b} {c' : C a' b'}
       → (f : (a : A) → (b : B a) → (c : C a b) → D a b c)
       → a == a' → b =h b' → c =h c' → (f a b c) =h (f a' b' c')
  apdo3 f id hid hid = hid

  pair=o : ∀ {l1 l2} {A : Set l1} {B : A -> Set l2} {p q : Σ B} -> (α : (fst p) == (fst q)) -> (snd p) =h (snd q) -> p == q
  pair=o {p = x , y} {q = .x , .y} id hid = id

  ap=o1 :  {l1 l2 : Level} {A : Set l1} {B B' : Set l2} → (B == B') → {M : A} 
       (f : A → B) (g : A → B') → f =h g → (M : A) → (f M) =h (g M)
  ap=o1 id f .f hid h = hid

  ap=o :  {l1 l2 : Level} {A A' : Set l1} {B B' : Set l2} → (B == B') → {M : A} {N : A'} 
       (f : A → B) (g : A' → B') → f =h g → M =h N → (f M) =h (g N)
  ap=o Beq {M} f g p hid = ap=o1 Beq {M} f g p M

  ap=od1 : {l1 l2 : Level} {A : Set l1} {B B' : A → Set l2} → (B == B') → {M : A} 
           (f : (x : A) → B x) (g : (x' : A) → B' x') → f =h g → (f M) =h (g M)
  ap=od1 id {M} f g hid = hid

  pair=oo : ∀ {l1 l2} {A A' : Set l1}
              {B : A -> Set l2}
              {B' : A' -> Set l2}
              → (B =h B')
              → {p : Σ B} {q : Σ B'}
          -> (α : (fst p) =h (fst q)) -> (snd p) =h (snd q) -> p =h q
  pair=oo hid {x , y} {.x , .y} hid hid = hid

  pair=h-fst : ∀ {l1 l2} {A : Set l1}
                 {B : A -> Set l2}
                 {B' : A -> Set l2}
                 → (_ : B =h B')
                 {p : Σ B} {q : Σ B'}
                 → p =h q → fst p =h fst q
  pair=h-fst hid hid = hid      

  uipoo : ∀ {l} {A A' B B' : Set l}
           → {x : A} {y : B} {x' : A'} {y' : B'}
             {p : x =h y} {q : x' =h y'} {r : x =h x'}
           → p =h q
  uipoo {p = hid} {q = hid} {r = hid} = hid

  uipo : ∀ {l} {A A' : Set l}
           {x : A} {y : A} {x' : A'} {y' : A'}
           {p : x == y} {q : x' == y'} {r : x =h x'}
         → p =h q
  uipo {p = id} {q = id} {r = hid} = hid


  record Iso {l1 l2 : Level} (A : Set l1) (B : Set l2) : Set (l1 ⊔ l2) where
    constructor iso
    field
      f : A → B
      g : B → A
      gf : (x : A) → g (f x) == x
      fg : (x : B) → f (g x) == x

  record isIso {l1 l2 : Level} (A : Set l1) (B : Set l2) (f : A → B) : Set (l1 ⊔ l2) where
    constructor iso
    field
      g : B → A
      gf : (x : A) → g (f x) == x
      fg : (x : B) → f (g x) == x

  eqIso :  {l1 : Level} {A : Set l1} {B : Set l1} → A == B → Iso A B
  eqIso p = iso (coe p) (coe (! p)) ((\ _ → ap= (transport-inv (\ X → X) p))) (\ _ → ap= (transport-inv-2 (\ X → X) p))

  _∘iso_ :  {l1 l2 l3 : Level} {A : Set l1} {B : Set l2} {C : Set l3} 
       → Iso B C
       → Iso A B 
       → Iso A C
  _∘iso_ (iso fb gb fgb gfb) (iso fa ga fga gfa) = iso (fb o fa) (ga o gb) (\ _ → fga _ ∘ ap ga (fgb _)) ((\ _ → gfb _ ∘ ap fb (gfa _)))



  iso-inv :  {l1 l2 : Level} {A : Set l1} {B : Set l2} 
       → Iso A B 
       → Iso B A
  iso-inv (iso f g Aeq Beq) = iso g f Beq Aeq

  ap-∘ :  {l1 l2 : Level} {A : Set l1} {B : Set l2} {M N P : A}
            (f : A → B) (p : M == N) (q : N == P)
            → ap f (q ∘ p) == (ap f q ∘ ap f p)
  ap-∘ f id id = id

  ap-o :  {l1 l2 l3 : Level} {A : Set l1} {B : Set l2} {C : Set l3} {M N : A}
            (f : A → B) (g : B → C) (p : M == N)
            → ap g (ap f p) == ap (\x → g (f x)) p
  ap-o f g id = id