{-# OPTIONS -WUnsupportedIndexedMatch #-}
open import 1Lab.Path.IdentitySystem.Interface
open import 1Lab.Path.IdentitySystem
open import 1Lab.HLevel.Closure
open import 1Lab.Type.Sigma
open import 1Lab.Univalence
open import 1Lab.HLevel
open import 1Lab.Equiv
open import 1Lab.Path
open import 1Lab.Type

open import Data.Maybe.Base
open import Data.Dec.Base
open import Data.Nat.Base

open import Meta.Invariant
module Data.Id.Base where

Inductive identity🔗

In cubical type theory, we generally use the path types to represent identifications. But in cubical type theory with indexed inductive types, we have a different — but equivalent — choice: the inductive identity type.

data _≡ᵢ_ {ℓ} {A : Type ℓ} (x : A) : A → Type ℓ where
  reflᵢ : x ≡ᵢ x

{-# BUILTIN EQUALITY _≡ᵢ_ #-}

To show that is equivalent to for every type we’ll show that _≡ᵢ_ and reflᵢ form an identity system regardless of the underlying type. Since Id is an inductive type, we can do so by pattern matching, which results in a very slick definition:

Id-identity-system
  : ∀ {ℓ} {A : Type ℓ}
  → is-identity-system (_≡ᵢ_ {A = A}) (λ _ → reflᵢ)
Id-identity-system .to-path      refláµ¢ = refl
Id-identity-system .to-path-over refláµ¢ = refl

Paths are, in many ways, more convenient than the inductive identity type: as a (silly) example, for paths, we have definitionally. But the inductive identity type has one property which sets it apart from paths: regularity. Transport along the reflexivity path is definitionally the identity:

substᵢ : ∀ {ℓ ℓ'} {A : Type ℓ} (P : A → Type ℓ') {x y : A}
       → x ≡ᵢ y → P x → P y
substáµ¢ P refláµ¢ x = x

_ : ∀ {ℓ} {A : Type ℓ} {x : A} → substᵢ (λ x → x) reflᵢ x ≡ x
_ = refl
_ = _≡_
Id≃path : ∀ {ℓ} {A : Type ℓ} {x y : A} → (x ≡ᵢ y) ≃ (x ≡ y)
Id≃path {ℓ} {A} {x} {y} =
  identity-system-gives-path (Id-identity-system {â„“ = â„“} {A = A}) {a = x} {b = y}

module Id≃path {ℓ} {A : Type ℓ} = Ids (Id-identity-system {A = A})

In the 1Lab, we prefer _≡_ over _≡ᵢ_ — which is why there is no comprehensive toolkit for working with the latter. But it can still be used when we want to avoid transport along reflexivity, for example, when working with decidable equality of concrete (indexed) types like Fin.

Discreteᵢ : ∀ {ℓ} → Type ℓ → Type ℓ
Discreteᵢ A = (x y : A) → Dec (x ≡ᵢ y)

Discreteᵢ→discrete : ∀ {ℓ} {A : Type ℓ} → Discreteᵢ A → Discrete A
Discreteᵢ→discrete d {x} {y} with d x y
... | yes refláµ¢ = yes refl
... | no ¬x=y   = no λ p → ¬x=y (Id≃path.from p)

is-set→is-setᵢ : ∀ {ℓ} {A : Type ℓ} → is-set A → (x y : A) (p q : x ≡ᵢ y) → p ≡ q
is-set→is-setᵢ A-set x y p q = Id≃path.injective (A-set _ _ _ _)

≡ᵢ-is-hlevel' : ∀ {ℓ} {A : Type ℓ} {n} → is-hlevel A (suc n) → (x y : A) → is-hlevel (x ≡ᵢ y) n
≡ᵢ-is-hlevel' {n = n} ahl x y = subst (λ e → is-hlevel e n) (sym (ua Id≃path)) (Path-is-hlevel' n ahl x y)
discrete-id : ∀ {ℓ} {A : Type ℓ} {x y : A} → Dec (x ≡ y) → Dec (x ≡ᵢ y)
discrete-id {x = x} {y} (yes p) = yes (subst (x ≡ᵢ_) p reflᵢ)
discrete-id {x = x} {y} (no ¬p) = no λ { reflᵢ → absurd (¬p refl) }

opaque
  _≡ᵢ?_ : ∀ {ℓ} {A : Type ℓ} ⦃ _ : Discrete A ⦄ (x y : A) → Dec (x ≡ᵢ y)
  x ≡ᵢ? y = discrete-id (x ≡? y)

  ≡ᵢ?-default : ∀ {ℓ} {A : Type ℓ} {x y : A} {d : Discrete A} → (_≡ᵢ?_ ⦃ d ⦄ x y) ≡ discrete-id d
  ≡ᵢ?-default = refl

  ≡ᵢ?-yes : ∀ {ℓ} {A : Type ℓ} {x : A} {d : Discrete A} → (_≡ᵢ?_ ⦃ d ⦄ x x) ≡ yes reflᵢ
  ≡ᵢ?-yes {d = d} = case d return (λ d → discrete-id d ≡ yes reflᵢ) of λ where
    (yes a) → ap yes (is-set→is-setᵢ (Discrete→is-set d) _ _ _ _)
    (no ¬a) → absurd (¬a refl)

{-# REWRITE ≡ᵢ?-default ≡ᵢ?-yes #-}

Discrete-inj'
  : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} (f : A → B)
  → (∀ {x y} → f x ≡ᵢ f y → x ≡ᵢ y)
  → ⦃ _ : Discrete B ⦄
  → Discrete A
Discrete-inj' f inj {x} {y} =
  invmap (λ p → Id≃path.to (inj p)) (λ x → Id≃path.from (ap f x)) (f x ≡ᵢ? f y)

instance
  Discrete-Σ
    : ∀ {ℓ ℓ'} {A : Type ℓ} {B : A → Type ℓ'}
    → ⦃ _ : Discrete A ⦄
    → ⦃ _ : ∀ {x} → Discrete (B x) ⦄
    → Discrete (Σ A B)
  Discrete-Σ {B = B} {x = a , b} {a' , b'} = case a ≡ᵢ? a' of λ where
    (yes reflᵢ) → case b ≡? b' of λ where
      (yes q) → yes (ap₂ _,_ refl q)
      (no ¬q) → no λ p → ¬q (Σ-inj-set (Discrete→is-set auto) p)
    (no ¬p) → no λ p → ¬p (Id≃path.from (ap fst p))

abstract instance
  H-Level-Id
    : ∀ {ℓ n} {S : Type ℓ} ⦃ s : H-Level S (suc n) ⦄ {x y : S}
    → H-Level (x ≡ᵢ y) n
  H-Level-Id {n = n} = hlevel-instance (Equiv→is-hlevel n Id≃path (hlevel n))

substáµ¢-filler-set
  : ∀ {ℓ ℓ'} {A : Type ℓ} (P : A → Type ℓ')
  → is-set A
  → {a : A}
  → (p : a ≡ᵢ a)
  → ∀ x → x ≡ substᵢ P p x
substᵢ-filler-set P is-set-A p x = subst (λ q → x ≡ substᵢ P q x) (is-set→is-setᵢ is-set-A _ _ reflᵢ p) refl

record Recalláµ¢
  {a b} {A : Type a} {B : A → Type b}
  (f : (x : A) → B x) (x : A) (y : B x)
  : Type (a ⊔ b)
  where
    constructor ⟪_⟫ᵢ
    field
      eq : f x ≡ᵢ y

recalláµ¢
  : ∀ {a b} {A : Type a} {B : A → Type b}
  → (f : (x : A) → B x) (x : A)
  → Recallᵢ f x (f x)
recallᵢ f x = ⟪ reflᵢ ⟫ᵢ

symᵢ : ∀ {a} {A : Type a} {x y : A} → x ≡ᵢ y → y ≡ᵢ x
symáµ¢ refláµ¢ = refláµ¢

_∙ᵢ_ : ∀ {a} {A : Type a} {x y z : A} → x ≡ᵢ y → y ≡ᵢ z → x ≡ᵢ z
reflᵢ ∙ᵢ q = q

apáµ¢
  : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'}
  → {x y : A}
  → (f : A → B)
  → x ≡ᵢ y → f x ≡ᵢ f y
apáµ¢ f refláµ¢ = refláµ¢


Jáµ¢
  : ∀ {ℓ ℓ'} {A : Type ℓ} {x : A} (P : (y : A) → x ≡ᵢ y → Type ℓ')
  → P x reflᵢ
  → ∀ {y} (p : x ≡ᵢ y)
  → P y p
Jáµ¢ P prefl refláµ¢ = prefl