-- Plump ordinals as presented by Shulman
-- https://homotopytypetheory.org/2014/02/22/surreals-plump-ordinals/
--
-- Implementation based on an implementation of Aczel sets by Andreas Abel.
module Ordinal.Shulman where

open import Data.Sum using ([_,_]′)
open import Induction.WellFounded as WfRec using (Acc ; acc ; WellFounded)
open import Level using (Lift ; lift ; lower)
open import Relation.Binary using (IsEquivalence)
open import Relation.Nullary using (¬_)

open import Ordinal.HoTT using (IsOrdinal ; IsExtensional ; _↔_ ; forth ; back)
open import Util.Prelude


-- Definition of ordinals, equality, orders
------------------------------------------------------------------------

-- Ordinals are infinitely branching well-founded trees.
-- The branching type is given at each node.

data Ord  : Set (lsuc ) where
  limSuc : (I : Set ) (els : I  Ord )  Ord 

-- Branching type

Br :  {} (a : Ord )  Set 
Br (limSuc I _) = I

-- Elements

els :  {} (a : Ord ) (i : Br a)  Ord 
els (limSuc _ f) = f

syntax els a i = a ` i

lift-Ord :  {a }  Ord   Ord (a ⊔ℓ )
lift-Ord {a} (limSuc I f) = limSuc (Lift a I) λ i  lift-Ord {a} (f (lower i))

-- Equality and orders

mutual
  _<_ :  {} (a b : Ord )  Set 
  a < limSuc _ f = ∃[ i ] (a  f i)

  _≤_  :  {} (a b : Ord )  Set 
  limSuc _ f  b =  i  f i < b

_≅_ :  {} (a b : Ord )  Set 
a  b = (a  b) × (b  a)

_≮_ :  {} (a b : Ord )  Set 
a  b = ¬ (a < b)

_≇_ :  {} (a b : Ord )  Set 
a  b = ¬ (a  b)

-- Intro/Elim rules for </≤ (for nicer proofs below)

<-intro :  {} {a b : Ord }  ∃[ i ] (a  (b ` i))  a < b
<-intro {b = limSuc I f} p = p

<-elim :  {} {a b : Ord }  a < b  ∃[ i ] (a  (b ` i))
<-elim {b = limSuc I f} p = p

≤-intro :  {} {a b : Ord }  (∀ i  (a ` i) < b)  a  b
≤-intro {a = limSuc I f} p = p

≤-elim :  {} {a b : Ord }  a  b  (∀ i  (a ` i) < b)
≤-elim {a = limSuc I f} p = p

-- Reflexivity

≤-refl :  {} {a : Ord }  a  a
≤-refl {a = limSuc _ f} i = i , ≤-refl

≅-refl :  {} {a : Ord }  a  a
≅-refl = ≤-refl , ≤-refl

-- < implies ≤

<→≤ :  {} {a b : Ord }  a < b  a  b
<→≤ {} {limSuc A fa} {limSuc B fb} (i , fa<fb) j = i , <→≤ (fa<fb j)

-- Transitivity

mutual
  <-trans-≤ :  {} {a b c : Ord }  a < b  b  c  a < c
  <-trans-≤ {b = limSuc _ f} (i , p) h = ≤-trans-< p (h i)

  ≤-trans-< :  {} {a b c : Ord }  a  b  b < c  a < c
  ≤-trans-< {c = limSuc _ f} p (i , q) = i , ≤-trans p q

  ≤-trans :  {} {a b c : Ord }  a  b  b  c  a  c
  ≤-trans {a = limSuc _ f} h q i = <-trans-≤ (h i) q

<-trans :  {} {a b c : Ord }  a < b  b < c  a < c
<-trans {} {a} {b} {limSuc C fc} a<b (i , b≤fci) = i , <→≤ (<-trans-≤ a<b b≤fci)

≅-trans :  {} {a b c : Ord } (d : a  b) (e : b  c)  a  c
≅-trans (p , p′) (q , q′) = ≤-trans p q , ≤-trans q′ p′

-- Symmetry

≅-sym :  {} {a b : Ord } (p : a  b)  b  a
≅-sym (p , p′) = p′ , p

-- ≅ is an equivalence relation.

≅-equiv :  {}  IsEquivalence (_≅_ {})
≅-equiv = record
  { refl = ≅-refl
  ; sym = ≅-sym
  ; trans = ≅-trans
  }

-- < is 'extensional'.

<-ext-≤ :  {} {a b : Ord }  (∀ c  c < a  c < b)  a  b
<-ext-≤ {a = limSuc I els} p i = p (els i) (i , ≤-refl)

<-ext :  {}  IsExtensional {} _≅_ _<_
<-ext p = <-ext-≤  c  forth (p c)) , <-ext-≤  c  back (p c))

-- Alternative interpretation of ≤ in terms of <

≤-intro′ :  {} {b c : Ord }  (∀ {a}  a < b  a < c)  b  c
≤-intro′ {b = limSuc _ f} cast i = cast (i , ≤-refl)

≤-elim′ :  {} {b c : Ord }  b  c   {a}  a < b  a < c
≤-elim′ b≤c a<b = <-trans-≤ a<b b≤c

-- Compatibility of ≤ with ≅

≤-congˡ :  {} {a b c : Ord }  a  b  a  c  b  c
≤-congˡ {}  (a≤b , b≤a) a≤c = ≤-trans b≤a a≤c

≤-congʳ :  {} {a b c : Ord }  b  c  a  b  a  c
≤-congʳ (b≤c , c≤b) a≤b = ≤-trans a≤b b≤c

-- Compatibility of < with ≅

<-congʳ :  {} {a b c : Ord }  b  c  a < b  a < c
<-congʳ (b≤c , c≤b) a<b = <-trans-≤ a<b b≤c

<-congˡ :  {} {a b c : Ord }  a  b  a < c  b < c
<-congˡ (a≤b , b≤a) a<c = ≤-trans-< b≤a a<c

-- Foundation: a ≤ b implies b ≮ a

≤-found :  {} {a b : Ord }  a  b  b  a
≤-found {} {limSuc A fa} {b} a≤b (i , b≤fai) = ≤-found b≤fai (a≤b i)

-- Thus, a ≮ a.

<-irr :  {} {a : Ord }  a  a
<-irr = ≤-found ≤-refl

-- Predicates over ordinals (need to respect equality)

IsPred :  {} (P : Ord   Set )  Set (lsuc )
IsPred {} P = {a b : Ord }  a  b  P a  P b

record Pred  : Set (lsuc ) where
  constructor pred
  field
    _!_  : Ord   Set 
    resp : IsPred _!_

open Pred

-- <-induction.

<-acc-≤ :  {} {a b : Ord }  a  b  Acc _<_ b  Acc _<_ a
<-acc-≤ {} {limSuc A fa} {b} fai<b (acc rs) = acc λ where
  x (i , x≤fai)  rs x (≤-trans-< x≤fai (fai<b i))

<-wf :  {}  WellFounded (_<_ {})
<-wf (limSuc I f) = acc λ { x (i , x≤fi)  <-acc-≤ x≤fi (<-wf (f i)) }

<-ind :  { ℓ′} (P : Ord   Set ℓ′)
   (∀ a  (∀ b  b < a  P b)  P a)
    a  P a
<-ind = WfRec.All.wfRec <-wf _

-- Ordinals are ordinals (in the sense of the HoTT book).

isOrdinal :  {}  IsOrdinal (Ord )  
isOrdinal = record
  { _≈_ = _≅_
  ; ≈-equiv = ≅-equiv
  ; _<_ = _<_
  ; <-wf = <-wf
  ; <-ext = <-ext
  ; <-trans = <-trans
  }

-- Constructions on ordinals
------------------------------------------------------------------------

-- Zero

ozero :  {}  Ord 
ozero {} = limSuc (Lift  ) λ()

-- Successor?

osuc :  {}  Ord   Ord 
osuc {} a = limSuc (Lift  ) λ _  a

-- Lo and behold!
osuc-mon-< :  {} {a b : Ord }  a < b  osuc a < osuc b
osuc-mon-< a<b = _ , λ _  a<b

osuc-mon-≤ :  {} {a b : Ord }  a  b  osuc a  osuc b
osuc-mon-≤ a≤b _ = _ , a≤b

osuc-cong :  {} {a b : Ord }  a  b  osuc a  osuc b
osuc-cong (a≤b , b≤a) = osuc-mon-≤ a≤b , osuc-mon-≤ b≤a

-- Maximum/Supremum

_⊔_ :  {} (a b : Ord )  Ord 
a  b = limSuc (_  _) λ where
  (inj₁ i)  a ` i
  (inj₂ j)  b ` j

⊔-introˡ :  {} a {b c : Ord }  a < b  a < (b  c)
⊔-introˡ a {limSuc _ f} (i , e) = inj₁ i , e

⊔-introʳ :  {} a {b c : Ord }  a < c  a < (b  c)
⊔-introʳ a {c = limSuc _ g} (i , e) = inj₂ i , e

⊔-≤-introˡ :  {} a {b c : Ord }  a  b  a  (b  c)
⊔-≤-introˡ a a≤b = ≤-intro λ i  ⊔-introˡ _ (≤-elim a≤b i)

⊔-≤-introˡ′ :  {} {a : Ord } b  a  (a  b)
⊔-≤-introˡ′ b = ⊔-≤-introˡ _ ≤-refl

⊔-≤-introʳ :  {} a {b c : Ord }  a  c  a  (b  c)
⊔-≤-introʳ a a≤c = ≤-intro λ i  ⊔-introʳ _ (≤-elim a≤c i)

⊔-≤-introʳ′ :  {} a {b : Ord }  b  (a  b)
⊔-≤-introʳ′ a = ⊔-≤-introʳ _ ≤-refl

⊔-elim :  {} {a b c : Ord }  c < (a  b)  (c < a)  (c < b)
⊔-elim {a = limSuc _ f}                  (inj₁ i , e) = inj₁ (i , e)
⊔-elim {a = limSuc _ _} {b = limSuc _ g} (inj₂ i , e) = inj₂ (i , e)

⊔-case :  {} {a b c : Ord }
   c < (a  b)
    {q} {Q : Set q}
   (c < a  Q)
   (c < b  Q)  Q
⊔-case p left right = [ left , right ]′ (⊔-elim p)

⊔-split :  { q} {Q : Set q} {a b c : Ord }
   (c < a  Q)
   (c < b  Q)
   c < (a  b)  Q
⊔-split left right p = ⊔-case p left right

⊔-mon :  {} {a a′ b b′ : Ord }  a  a′  b  b′  (a  b)  (a′  b′)
⊔-mon a≤a′ b≤b′ = ≤-intro′
  (⊔-split
     c<a  ⊔-introˡ _ (≤-elim′ a≤a′ c<a))
     c<b  ⊔-introʳ _ (≤-elim′ b≤b′ c<b)))

⊔-cong :  {} {a a′ b b′ : Ord }  a  a′  b  b′  (a  b)  (a′  b′)
⊔-cong (a≤a′ , a′≤a) (b≤b′ , b′≤b) = ⊔-mon a≤a′ b≤b′ , ⊔-mon a′≤a b′≤b

⊔-<→LEM :  {}
   ({α α′ β : Ord }  α < β  α′ < β  (α  α′) < β)
   (A : Set )  A  ¬ A
⊔-<→LEM {} p A
  = let α<β : α < β
        α<β = lift true , ≤-refl
        α′<β : α′ < β
        α′<β = lift false , ≤-refl in
    go (p α<β α′<β)
  where
    oone = osuc ozero
    α = limSuc A λ _  oone
    α′ = oone
    β = limSuc (Lift  Bool) λ { (lift true)  α ; (lift false)  α′ }

    go : (α  α′) < β  A  ¬ A
    go (lift true , α⊔α′≤α) = inj₁ (proj₁ (α⊔α′≤α (inj₂ _)))
    go (lift false , α⊔α′≤α′) = inj₂ λ a  lower (proj₁ (proj₂ (α⊔α′≤α′ (inj₁ a)) _))

-- Supremum of a family of ordinals

⨆ᶠ :  {} {I : Set } (f : I  Ord )  Ord 
⨆ᶠ {} {I} f = limSuc (∃[ i ] Br (f i)) λ { (i , j)  f i ` j }

⨆ᶠ-intro :  {} {I : Set } (f : I  Ord ) {c : Ord } {i : I}
   c < f i  c < ⨆ᶠ f
⨆ᶠ-intro f {c} {i} c<fi
  = let j , c≤ = <-elim c<fi in
    (i , j) , c≤

⨆ᶠ-elim :  {} {I : Set } (f : I  Ord ) {c : Ord }
   c < ⨆ᶠ f  ∃[ i ] (c < f i)
⨆ᶠ-elim _ ((i , j) , e) = i , <-intro (j , e)

⨆ᶠ-mon :  {} {I : Set } {f f′ : I  Ord }
   (∀ i  f i  f′ i)  ⨆ᶠ f  ⨆ᶠ f′
⨆ᶠ-mon {f = f} {f′} p = ≤-intro′ λ c<⨆ᶠf 
  let i , q = ⨆ᶠ-elim f c<⨆ᶠf in
  ⨆ᶠ-intro f′ (≤-elim′ (p i) q)

⨆ᶠ-cong :  {} {I : Set } {f f′ : I  Ord }
   (∀ i  f i  f′ i)  ⨆ᶠ f  ⨆ᶠ f′
⨆ᶠ-cong p = ⨆ᶠ-mon  i  proj₁ (p i))
          , ⨆ᶠ-mon  i  proj₂ (p i))

-- Supremum of all ordinals smaller than some given ordinal

 :  {} (a : Ord )  Ord 
 (limSuc _ f) = ⨆ᶠ f

⨆-intro :  {} {a b : Ord }  b < a  b   a
⨆-intro {a = limSuc A fa} {b = limSuc B fb} (i , b≤fi) = ≤-intro λ j 
  let k , p = <-elim (b≤fi j) in _ , p

⨆-elim :  {} {a c : Ord }  c <  a  ∃[ b ] ((b < a) × (c < b))
⨆-elim {a = limSuc _ f} ((i , j) , c≤) = f i , (i , ≤-refl) , <-intro (_ , c≤)