Jonathan Sterling, started 22 March, 2023.

Based on Egbert Rijke's "Introduction to Homotopy Type Theory".

\begin{code}

{-# OPTIONS --safe --without-K --exact-split #-}

module UF.IdentitySystems where

open import MLTT.Spartan
open import UF.Base
open import UF.Embeddings
open import UF.Equiv
open import UF.FunExt
open import UF.Retracts
open import UF.Subsingletons
open import UF.PairFun as PairFun

record Has-Id-Sys {𝓦} (A : 𝓤 ̇ ) (a : A) (fam : A → 𝓦 ̇) : 𝓤ω where
 field
  ctr : fam a
  ind : {𝓥 : Universe} (P : (x : A) (q : fam x) → 𝓥 ̇) (p : P a ctr) (x : A) (q : fam x) → P x q
  ind-β : {𝓥 : Universe} (P : (x : A) (q : fam x) → 𝓥 ̇) (p : P a ctr) → ind P p a ctr = p

 to-= : (x : A) → fam x → a = x
 to-= = ind _ refl

 from-= : (x : A) → a = x → fam x
 from-= x refl = ctr

 to-=-is-equiv : (x : A) → is-equiv (to-= x)
 pr₁ (pr₁ (to-=-is-equiv x)) = from-= x
 pr₂ (pr₁ (to-=-is-equiv x)) refl = ind-β _ _
 pr₁ (pr₂ (to-=-is-equiv x)) = from-= x
 pr₂ (pr₂ (to-=-is-equiv x)) q = aux x q
  where
   aux : (x : A) (q : fam x) → from-= x (to-= x q) = q
   aux = ind _ (ap (from-= a) (ind-β _ _))

record Id-Sys 𝓦 (A : 𝓤 ̇ ) (a : A) : 𝓤ω where
 field
  fam : A → 𝓦  ̇
  sys : Has-Id-Sys A a fam
 open Has-Id-Sys sys public


Unbiased-Id-Sys : Universe → 𝓤 ̇ → 𝓤ω
Unbiased-Id-Sys 𝓦 A = (a : A) → Id-Sys 𝓦 A a


module from-path-characterization
  {A : 𝓤 ̇ }
  (Q : A → A → 𝓤 ̇ )
  (H : {x y : A} → (x = y) ≃ Q x y)
  (a : A)
 where
  open Id-Sys
  open Has-Id-Sys

  private
   Q-refl : {x : A} → Q x x
   Q-refl = eqtofun H refl

   aux
    : (P : (x : A) (q : Q a x) → 𝓥 ̇ )
    → (p : P a Q-refl)
    → (x : A)
    → (q : a = x)
    → P x (eqtofun H q)
   aux P p x refl = p

  id-sys : Id-Sys 𝓤 A a
  fam id-sys = Q a
  ctr (sys id-sys) = Q-refl
  ind (sys id-sys) P p x q =
   transport (P x)
    (inverses-are-sections _ (eqtofun- H) q)
    (aux P p x (back-eqtofun H q))
  ind-β (sys id-sys) P p =
   ap gen
    (Aux-is-prop
     (back-eqtofun H Q-refl ,
      inverses-are-sections _ (eqtofun- H)  Q-refl)
     (refl , refl))
   where
    Aux = Σ ϕ ꞉ a = a , eqtofun H ϕ = Q-refl

    Aux-singl : singleton-type' refl ≃ Aux
    Aux-singl =
     pair-fun-equiv (≃-refl (a = a)) λ ϕ →
     ap (eqtofun H) ,
     embedding-gives-embedding' _
      (equivs-are-embeddings _ (eqtofun- H))
      ϕ
      refl

    Aux-is-prop : is-prop Aux
    Aux-is-prop =
     retract-of-prop
      (≃-gives-◁ (≃-sym Aux-singl))
      (singleton-types'-are-props refl)

    gen : Aux → P a Q-refl
    gen (ϕ , ψ ) = transport (P a) ψ (aux P p a ϕ)


module _ 𝓦 𝓦' (A : 𝓤 ̇ ) (B : A → 𝓥 ̇ ) where
 record Dep-Id-Sys {a : A} ([a] : Id-Sys 𝓦 A a) (b : B a) : 𝓤ω where
  private
   module [a] = Id-Sys [a]
  field
   fam : (x : A) (q : [a].fam x) (y : B x) → 𝓦' ̇
   sys : Has-Id-Sys (B a) b (fam a [a].ctr)

  open Has-Id-Sys sys public


module _
  {A : 𝓤 ̇ } {B : A → 𝓥 ̇ }
  {a : A} {b : B a}
  ([a] : Id-Sys 𝓦 A a)
  ([b] : Dep-Id-Sys 𝓦 𝓦' A B [a] b)
 where
  module [a] = Id-Sys [a]
  module [b] = Dep-Id-Sys [b]

  open Id-Sys
  open Has-Id-Sys

  pair-id-sys : Id-Sys (𝓦 ⊔ 𝓦') (Σ B) (a , b)
  fam pair-id-sys (x , y) = Σ ϕ ꞉ [a].fam x , [b].fam x ϕ y
  pr₁ (ctr (sys pair-id-sys)) = [a].ctr
  pr₂ (ctr (sys pair-id-sys)) = [b].ctr
  ind (sys pair-id-sys) P p =
   λ (x , y) (ϕ , ψ) → aux x ϕ y ψ
   where
    aux : (x : A) (ϕ : [a].fam x) (y : B x) (ψ : [b].fam x ϕ y) → P (x , y) (ϕ , ψ)
    aux = [a].ind _ ([b].ind _ p)
  ind-β (sys pair-id-sys) P p =
   happly (happly ([a].ind-β _ _) b) [b].ctr ∙ [b].ind-β _ _

module _ (A : 𝓤 ̇ ) where
 open Id-Sys
 open Has-Id-Sys

 =-id-sys : Unbiased-Id-Sys 𝓤 A
 fam (=-id-sys a) = a =_
 ctr (sys (=-id-sys a)) = refl
 ind (sys (=-id-sys a)) P p x refl = p
 ind-β (sys (=-id-sys a)) _ _ = refl

module _ (fe : funext 𝓤 𝓥) {A : 𝓤 ̇ } {B : 𝓥 ̇ } (f : A → B) where
 homotopy-id-sys : Id-Sys (𝓤 ⊔ 𝓥) (A → B) f
 homotopy-id-sys = from-path-characterization.id-sys _∼_ (happly-≃ fe) f

\end{code}