text:
{-# OPTIONS --cubical --no-import-sorts --safe --guardedness #-}
module Cubical.Codata.Conat.Bounded where

open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Univalence

open import Cubical.Codata.Conat.Base
  renaming (zero to czero; suc to csuc)
open import Cubical.Codata.Conat.Properties

open import Cubical.Data.Empty as Empty
open import Cubical.Data.Sigma
open import Cubical.Data.Sum hiding (rec)
open import Cubical.Data.Unit

open import Cubical.Relation.Nullary

open import Cubical.Data.Nat as Nat
import Cubical.Data.Fin.Recursive as Fin

private variable ℓ : Level

_≺_ : ℕ → Conat → Type _
_≺′_ : ℕ → Conat′ → Type _

n ≺ c = n ≺′ force c
_ ≺′ czero = ⊥
zero  ≺′ csuc _ = Unit
suc n ≺′ csuc c = n ≺ c

isProp≺ : ∀ n c → isProp (n ≺ c)
isProp≺′ : ∀ n c → isProp (n ≺′ c)
isProp≺ n c = isProp≺′ n (force c)
isProp≺′ n           czero = isProp⊥
isProp≺′ zero    (csuc  _) = isPropUnit
isProp≺′ (suc n) (csuc c') = isProp≺ n c'

isPropDep≺ : ∀ c → isPropDep (_≺ c)
isPropDep≺ c = isOfHLevel→isOfHLevelDep 1 (λ n → isProp≺ n c) {_} {_}

isPropDep≺′ : ∀ c → isPropDep (_≺′ c)
isPropDep≺′ c = isOfHLevel→isOfHLevelDep 1 (λ n → isProp≺′ n c) {_} {_}

private
  apart : ℕ → ℕ → Type
  apart zero zero = ⊥
  apart (suc m) (suc n) = apart m n
  apart _ _ = Unit

  ≢→apart : (i j : ℕ) → ¬ i ≡ j → apart i j
  ≢→apart zero zero ¬p = ¬p refl
  ≢→apart (suc i) (suc j) ¬p = ≢→apart i j (¬p ∘ cong suc)
  ≢→apart zero (suc j) _ = _
  ≢→apart (suc i) zero _ = _

  apart→≢ : (i j : ℕ) → apart i j → ¬ i ≡ j
  apart→≢ (suc i) zero _ = snotz
  apart→≢ zero (suc j) _ = znots
  apart→≢ (suc i) (suc j) i#j = apart→≢ i j i#j ∘ cong predℕ

  isPropApart : ∀ m n → isProp (apart m n)
  isPropApart 0 0 = isProp⊥
  isPropApart (suc m) (suc n) = isPropApart m n
  isPropApart (suc _) 0 = isPropUnit
  isPropApart 0 (suc _) = isPropUnit

_#_ : ∀{P : ℕ → Type ℓ} → (l r : Σ ℕ P) → Type
(m , _) # (n , _) = apart m n

#→≢ : ∀{P : ℕ → Type ℓ} → (l r : Σ ℕ P) → l # r → ¬ l ≡ r
#→≢ (i , _) (j , _) d = apart→≢ i j d ∘ cong fst

isProp# : ∀{P : ℕ → Type ℓ} (l r : Σ ℕ P) → isProp (l # r)
isProp# (m , _) (n , _) = isPropApart m n

isProp#Depᵣ : ∀{P : ℕ → Type ℓ} (r : Σ ℕ P) → isPropDep (_# r)
isProp#Depᵣ r = isOfHLevel→isOfHLevelDep 1 (λ l → isProp# l r) {_} {_}

Bounded : Conat → Type
Bounded m = Σ[ n ∈ ℕ ] n ≺ m

Bounded′ : Conat′ → Type
Bounded′ m = Σ[ n ∈ ℕ ] n ≺′ m

discreteB′ : ∀ m → (i j : Bounded′ m) → (i ≡ j) ⊎ (i # j)
discreteB′ m (i , i≺m) (j , j≺m) with discreteℕ i j
... | yes p = inl λ i → p i , isPropDep≺′ m i≺m j≺m p i
... | no ¬p = inr (≢→apart i j ¬p)

≺∞ : ∀ n → n ≺ ∞
≺∞ zero = _
≺∞ (suc n) = ≺∞ n

Σ≺∞≃ℕ : Bounded ∞ ≃ ℕ
Σ≺∞≃ℕ = isoToEquiv λ where
    .fun → fst
    .inv n → n , ≺∞ n
    .rightInv _ → refl
    .leftInv (n , p) i → λ where
      .fst → n
      .snd → isProp≺ n ∞ (≺∞ n) p i
  where open Iso

Σ≺∞≡ℕ : Bounded ∞ ≡ ℕ
Σ≺∞≡ℕ = ua Σ≺∞≃ℕ

_≺?_ : ∀ n c → Dec (n ≺ c)
n ≺? c with force c
_     ≺? c |  czero = no (idfun ⊥)
zero  ≺? c | csuc d = yes _
suc n ≺? c | csuc d = n ≺? d

≺-pred : ∀ n c → suc n ≺ c → n ≺ c
≺-pred n c sn≺c with force c
≺-pred    zero c sn≺c | csuc d = _
≺-pred (suc n) c sn≺c | csuc d = ≺-pred n d sn≺c

≺?-yes : ∀ n c → (p : n ≺ c) → n ≺? c ≡ yes p
≺?-yes n c p with force c
≺?-yes   zero  c p | csuc c' = refl
≺?-yes (suc n) c p | csuc c' = ≺?-yes n c' p

∀≺-same : ∀ m n → (∀ k → (k ≺ m) ≡ (k ≺ n)) → m ≡ n
∀≺-same m n ∀≺ i .force with force m | force n
... |  czero |  czero = czero
... | csuc o | csuc p = csuc (∀≺-same o p (∀≺ ∘ suc) i)
... | csuc o |  czero
  = Empty.rec {A = csuc o ≡ czero} (transport (∀≺ 0) _) i
... |  czero | csuc p
  = Empty.rec {A = czero ≡ csuc p} (transport⁻ (∀≺ 0) _) i

Bounded→Fin : ∀ m → Bounded (embed m) → Fin.Fin m
Bounded→Fin (suc m) (0 , 0≺m) = Fin.zero
Bounded→Fin (suc m) (suc n , n≺m) = Fin.suc (Bounded→Fin m (n , n≺m))

module Untangle
    {m n}
    (f : Bounded′ (csuc m) → Bounded′ (csuc n))
    (g : Bounded′ (csuc n) → Bounded′ (csuc m))
    (rinv : section f g)
    (linv : retract f g)
  where
  bzro : ∀{k} → Bounded′ (csuc k)
  bzro = (zero , _)

  bsuc : ∀{k} → Bounded k → Bounded′ (csuc k)
  bsuc (l , l≺k) = (suc l , l≺k)

  #-f : ∀ v u → v # u → f v # f u
  #-f v u v#u with discreteB′ (csuc n) (f v) (f u)
  ... | inr fv#fu = fv#fu
  ... | inl fv≡fu
    = rec (#→≢ v u v#u (sym (linv v) ∙∙ cong g (fv≡fu) ∙∙ linv u))

  #-g : ∀ v u → v # u → g v # g u
  #-g v u v#u with discreteB′ (csuc m) (g v) (g u)
  ... | inr gv#gu = gv#gu
  ... | inl gv≡gu
    = rec (#→≢ v u v#u (sym (rinv v) ∙∙ cong f (gv≡gu) ∙∙ rinv u))

  #-fg : ∀ v u → v # u → f (g v) # f (g u)
  #-fg v u = #-f (g v) (g u) ∘ #-g v u

  #-gf : ∀ v u → v # u → g (f v) # g (f u)
  #-gf v u = #-g (f v) (f u) ∘ #-f v u

  default : ∀{k} → (v d : Bounded′ (csuc k)) → v # d → Bounded k
  default (suc l , l≺n) d _ = (l , l≺n)
  default (0 , _) (suc l , l≺n) _ = (l , l≺n)

  f- : Bounded m → Bounded n
  f- v = default (f (bsuc v)) (f bzro) (#-f (bsuc v) bzro _)

  g- : Bounded n → Bounded m
  g- v = default (g (bsuc v)) (g bzro) (#-g (bsuc v) bzro _)

  g-f-z : ∀ v u → g bzro ≡ bsuc v → g (bsuc u) ≡ bzro → g- u ≡ v
  g-f-z (l , l≺m) u p q with g (bsuc u) | g bzro | #-g (bsuc u) bzro _
  ... | zero , _ | suc k , k≺m | #gf = λ where
    i .fst → predℕ (p i .fst)
    i .snd → isPropDep≺ m k≺m l≺m (cong (predℕ ∘ fst) p) i
  ... | w@(suc k , k≺m) | dg | #gf = rec (snotz (cong fst q))

  g-f-s : ∀ v u → g (bsuc u) ≡ bsuc v → g- u ≡ v
  g-f-s (l , l≺m) u p with g (bsuc u) | #-g (bsuc u) bzro _
  ... | suc k , k≺m | #gf = λ where
    i .fst → predℕ (p i .fst)
    i .snd → isPropDep≺ m k≺m l≺m (cong (predℕ ∘ fst) p) i
  ... |  zero , k≺m | #gf = rec (znots (cong fst p))

  g-f- : ∀ v → g- (f- v) ≡ v
  g-f- v@(i , i≺m)
    with f (bsuc v) | linv (bsuc v) | #-f (bsuc v) bzro _
  ... | suc j , j≺m | p | #f = g-f-s v (j , j≺m) p
  ... | zero , _ | p | #f with f bzro | linv bzro
  ... | suc k , k≺n | q = g-f-z v (k , k≺n) p q

  f-g-z : ∀ v u → f bzro ≡ bsuc v → f (bsuc u) ≡ bzro → f- u ≡ v
  f-g-z (l , l≺n) u p q with f (bsuc u) | f bzro | #-f (bsuc u) bzro _
  ... | zero , _ | suc k , k≺n | #fg = λ where
    i .fst → predℕ (p i .fst)
    i .snd → isPropDep≺ n k≺n l≺n (cong (predℕ ∘ fst) p) i
  ... | w@(suc k , k≺m) | df | #fg = rec (snotz (cong fst q))

  f-g-s : ∀ v u → f (bsuc u) ≡ bsuc v → f- u ≡ v
  f-g-s (l , l≺n) u p with f (bsuc u) | #-f (bsuc u) bzro _
  ... | suc k , k≺n | _ = λ where
    i .fst → predℕ (p i .fst)
    i .snd → isPropDep≺ n k≺n l≺n (cong (predℕ ∘ fst) p) i
  ... |  zero , k≺m | _ = rec (znots (cong fst p))

  f-g- : ∀ v → f- (g- v) ≡ v
  f-g- v@(i , i≺n)
    with g (bsuc v) | rinv (bsuc v) | #-g (bsuc v) bzro _
  ... | suc j , j≺m | p | #g = f-g-s v (j , j≺m) p
  ... | zero , _ | p | #g with g bzro | rinv bzro
  ... | suc k , k≺m | q = f-g-z v (k , k≺m) p q

  open Iso
  iso- : Iso (Bounded m) (Bounded n)
  iso- .fun = f-
  iso- .inv = g-
  iso- .rightInv = f-g-
  iso- .leftInv = g-f-

untangled
  : ∀{m n}
  → Iso (Bounded′ (csuc m)) (Bounded′ (csuc n))
  → Iso (Bounded m) (Bounded n)
untangled isom = Untangle.iso- fun inv rightInv leftInv
  where open Iso isom

Bounded-inj-iso : ∀ m n → Iso (Bounded m) (Bounded n) → m ≡ n
Bounded-inj-iso m n theIso i .force with force m | force n
... | czero | czero = czero
... | csuc l | csuc r
  = csuc (Bounded-inj-iso l r (untangled theIso) i)
... | czero | csuc r
  = rec {A = czero ≡ csuc r} (Iso.inv theIso (zero , _) .snd) i
... | csuc l | czero
  = rec {A = csuc l ≡ czero} (Iso.fun theIso (zero , _) .snd) i

Bounded-inj : ∀ m n → Bounded m ≡ Bounded n → m ≡ n
Bounded-inj m n = Bounded-inj-iso m n ∘ pathToIso


text:
{-# OPTIONS --without-K --safe #-}

open import Categories.Category.Core using (Category)
open import Categories.Functor.Bifunctor using (Bifunctor)

module Categories.Category.Construction.Wedges {o ℓ e o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′}
  (F : Bifunctor (Category.op C) C D) where

open import Level

open import Categories.Category.Core using (Category)
open import Categories.Diagram.Wedge F

Wedges : Category (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′) (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′) e′
Wedges =  record
  { Obj = Wedge
  ; _⇒_ = Wedge-Morphism
  ; _≈_ = λ M N → u M ≈ u N
  ; id = Wedge-id
  ; _∘_ = Wedge-Morphism-∘
  ; assoc = assoc
  ; sym-assoc = sym-assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identity²
  ; equiv = record { refl = Equiv.refl ; sym = Equiv.sym ; trans = Equiv.trans }
  ; ∘-resp-≈ = ∘-resp-≈
  }
  where
  open Wedge-Morphism
  open Category D

ext: agda

max_stars_repo_name: Trebor-Huang/agda-categories

max_issues_repo_name: Code-distancing/agda-categories

max_forks_repo_name: Code-distancing/agda-categories