QIITOrd.Base

Ordinals as a quotient inductive-inductive type

This module is the foundation of the library. It defines the type Ord of ordinals — Brouwer trees — as a quotient inductive-inductive type (QIIT), mutually with its order _≤_, following Kraus, Nordvall Forsberg and Xu, Type-Theoretic Approaches to Ordinals. It also derives the two eliminators (elimProp, ≤-elimProp) that every later module is built from, and the basic order lemmas.

{-# OPTIONS --cubical --safe #-}

module QIITOrd.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Path
open import Cubical.Data.Nat as  using ()
open import Cubical.Data.Sigma
open import Cubical.Relation.Nullary using (¬_)
open import Cubical.Relation.Binary.Base using (Rel; module BinaryRelation)
open BinaryRelation using (isRefl'; isTrans')

We reuse the cubical library’s binary-relation vocabulary: Rel A B ℓ is the type of -valued relations, and BinaryRelation’s isRefl' / isTrans' are the (implicit-argument) reflexivity and transitivity predicates. We only ever need homogeneous relations Rel A A ℓ.

Sequences and bisimulation

A limit ordinal is built from a sequence ℕ → A. Two such sequences should give the same limit exactly when they are mutually cofinal — they bisimulate. f ≼ g says every f n is dominated by some g m (the existence is a propositional truncation ), and f ≈ g is bisimilarity: f ≼ g and g ≼ f. This is stated generally for any relation _≤_, so the same definitions serve both the order on ordinals and, later, the order on order-codes.

module Bisimulation { ℓ'} {A : Type } (_≤_ : Rel A A ℓ') where
  private Seq =   A

  _≼⟨_⟩_ : Seq    Seq  Type _
  f ≼⟨ n  g = ∃[ m   ] f n  g m

  _≼_ : Rel Seq Seq _
  f  g =  n  f ≼⟨ n  g

  _≈_ : Rel Seq Seq _
  f  g = f  g × g  f

A sequence is monotone when suc (f n) ≤ f (suc n), i.e. it strictly increases. A MonoSeq bundles a sequence with that proof, and f [ n ] projects out its n-th term. Limits will be taken only of monotone sequences.

module MonotonicSequence { ℓ'} {A : Type } (suc : A  A) (_≤_ : Rel A A ℓ') where
  private Seq =   A

  isMonoSeq : Seq  Type _
  isMonoSeq f =  n  suc (f n)  f (ℕ.suc n)

  MonoSeq : Type _
  MonoSeq = Σ[ f  Seq ] isMonoSeq f

  infix 30 _[_]
  _[_] : MonoSeq    A
  f [ n ] = fst f n

The QIIT definition

Ord and _≤_ are declared mutually: _≤_ already appears in the type of lim (through MonoSeq), and Ord appears in the type of _≤_. We first forward-declare both, plus a private copy pre-suc of the successor (needed to instantiate MonotonicSequence before suc itself is in scope), then open the two helper modules at _≤_ so that MonoSeq, _≼_, , _[_] are available.

data Ord : Type
data _≤_ : Rel Ord Ord ℓ-zero
private pre-suc : Ord  Ord

open Bisimulation _≤_ public
open MonotonicSequence pre-suc _≤_ public

variable
  α β γ : Ord
  f g h : MonoSeq
  n : 

Ord has the three ordinal formers — zero, suc, and lim of a monotone sequence — and two higher constructors that make it a QIIT: l≡l quotients bisimilar limits to be equal (the path constructor), and isSetOrd truncates Ord to a set, so all of its path structure is determined by these.

data Ord where
  zero     : Ord
  suc      : Ord  Ord
  lim      : MonoSeq  Ord
  l≡l      : fst f  fst g  lim f  lim g
  isSetOrd : isSet Ord

The order _≤_ is generated by: zero is least (z≤); suc is monotone (s≤s); lim f is an upper bound of its sequence and the least one (≤l and l≤); together with transitivity and the proof that _≤_ is propositional. The last two are constructors because _≤_ is defined simultaneously with Ord, so we cannot derive them after the fact.

data _≤_ where
  z≤      : zero  α
  s≤s     : α  β  suc α  suc β
  ≤l      : α  f [ n ]  α  lim f
  l≤      : (∀ n  f [ n ]  α)  lim f  α
  ≤-trans : isTrans' _≤_
  isProp≤ : isProp (α  β)

pre-suc = suc

This completes the QIIT.

Transfinite induction into propositions

The work-horse recursor elimProp is structural recursion on Ord into a proposition-valued family P. Because each P α is a proposition, the two higher constructors are discharged automatically: the l≡l case by isProp→PathP and the isSetOrd case by isProp→SquareP. The user only supplies the zero/suc/lim methods — and in the lim method the inductive hypothesis arrives already unpacked as ∀ n → P (f [ n ]). This unpacking is what later lets transitivity of the order-code be defined structurally.

elimProp :  {} {P : Ord  Type } 
  (∀ α  isProp (P α)) 
  P zero 
  (∀ {α}  P α  P (suc α)) 
  (∀ {f}  (∀ n  P (f [ n ]))  P (lim f)) 
  (α : Ord)  P α
elimProp Pprop Pz Ps Pl zero    = Pz
elimProp Pprop Pz Ps Pl (suc α) = Ps (elimProp Pprop Pz Ps Pl α)
elimProp Pprop Pz Ps Pl (lim f) = Pl λ n  elimProp Pprop Pz Ps Pl (fst f n)
elimProp Pprop Pz Ps Pl (l≡l {f} {g} f≈g i) = isProp→PathP
   j  Pprop (l≡l f≈g j))
  (Pl λ n  elimProp Pprop Pz Ps Pl (fst f n))
  (Pl λ n  elimProp Pprop Pz Ps Pl (fst g n)) i
elimProp Pprop Pz Ps Pl (isSetOrd _ _ p q i j) = isProp→SquareP
   i j  Pprop $ isSetOrd _ _ _ _ i j) refl refl
   i  elimProp Pprop Pz Ps Pl (p i))
   i  elimProp Pprop Pz Ps Pl (q i)) i j

Dually, ≤-elimProp is structural recursion on a derivation of α ≤ β into a proposition-valued family. Its l≤ method is the subtle one: it supplies, in addition to the induction hypotheses on the proofs f [ n ] ≤ α, the sequence’s monotonicity hypotheses ∀ n → P (snd f n). That extra hypothesis is exactly what encode≤ needs later, and is why a plain “induction on the derivation” is not enough.

≤-elimProp :  {} {P :  {α β}  α  β  Type } 
  (∀ {α β} (α≤β : α  β)  isProp (P α≤β)) 
  (∀ {α}  P (z≤ {α})) 
  (∀ {α β} (α≤β : α  β)  P α≤β  P (s≤s α≤β)) 
  (∀ {α f n} (α≤f : α  f [ n ])  P α≤f  P (≤l {f = f} α≤f)) 
  (∀ {f α} (f≤α :  n  f [ n ]  α)  (∀ n  P (f≤α n))  (∀ n  P (snd f n))  P (l≤ {f} f≤α)) 
  (∀ {α β γ} {α≤β : α  β} {β≤γ : β  γ}  P α≤β  P β≤γ  P (≤-trans α≤β β≤γ)) 
  (α≤β : α  β)  P α≤β
≤-elimProp Pprop Pz Ps Pu Pl Pt z≤          = Pz
≤-elimProp Pprop Pz Ps Pu Pl Pt (s≤s α≤β)   = Ps α≤β $ ≤-elimProp Pprop Pz Ps Pu Pl Pt α≤β
≤-elimProp Pprop Pz Ps Pu Pl Pt (≤l α≤f)    = Pu α≤f $ ≤-elimProp Pprop Pz Ps Pu Pl Pt α≤f
≤-elimProp Pprop Pz Ps Pu Pl Pt (l≤ {f} f≤) = Pl f≤
   n  ≤-elimProp Pprop Pz Ps Pu Pl Pt (f≤ n))
   n  ≤-elimProp Pprop Pz Ps Pu Pl Pt (snd f n))
≤-elimProp Pprop Pz Ps Pu Pl Pt (≤-trans α≤β β≤γ) = Pt
  (≤-elimProp Pprop Pz Ps Pu Pl Pt α≤β)
  (≤-elimProp Pprop Pz Ps Pu Pl Pt β≤γ)
≤-elimProp Pprop Pz Ps Pu Pl Pt (isProp≤ α≤β β≤γ i) = isProp→PathP
   i  Pprop (isProp≤ α≤β β≤γ i))
  (≤-elimProp Pprop Pz Ps Pu Pl Pt α≤β)
  (≤-elimProp Pprop Pz Ps Pu Pl Pt β≤γ) i

Derived order notations

The strict order is α < β := suc α ≤ β, and we set up the usual negated and flipped notations, plus a couple of small numerals.

Seq =   Ord
one = suc zero
two = suc one

_≢_ : Rel Ord Ord _
α  β = ¬ α  β

_≥_ : Rel Ord Ord _
α  β = β  α

_≰_ : Rel Ord Ord _
α  β = ¬ α  β

_≱_ : Rel Ord Ord _
α  β = ¬ β  α

_<_ : Rel Ord Ord _
α < β = suc α  β

_>_ : Rel Ord Ord _
α > β = β < α

_≮_ : Rel Ord Ord _
α  β = ¬ α < β

_≯_ : Rel Ord Ord _
α  β = ¬ β < α

Basic order properties

Reflexivity is the first real use of elimProp: it follows the constructors, with the limit case combining l≤ and ≤l. From it we get that equal ordinals are related, that every sequence element is its limit (f≤l, the upper-bound property as a closed term), and the one inversion that needs no encode-decode: from lim f ≤ α we read back f [ n ] ≤ α just by transitivity with f≤l.

≤-refl : isRefl' _≤_
≤-refl = elimProp  α  isProp≤ {α} {α}) z≤ s≤s  ih  l≤ λ n  ≤l (ih n)) _

≡⇒≤ : α  β  α  β
≡⇒≤ α≡β = subst (_≤ _) (sym α≡β) ≤-refl

f≤l : f [ n ]  lim f
f≤l = ≤l ≤-refl

l≤-inv : lim f  α   n  f [ n ]  α
l≤-inv l≤α n = ≤-trans f≤l l≤α

-reasoning

Equational-style reasoning combinators for chaining , <, and steps; these make the limit proofs below (and throughout the library) readable.

infixr 0 _≤⟨_⟩_ _<⟨_⟩_ _<⟨_⟩suc_ _=⟨_⟩_ _=˘⟨_⟩_
infix  1 _≤∎

_≤⟨_⟩_ : (α : Ord)  α  β  β  γ  α  γ
_≤⟨_⟩_ _ = ≤-trans

_<⟨_⟩_ : (α : Ord)  α < β  β  γ  α < γ
_<⟨_⟩_ _ = ≤-trans

_<⟨_⟩suc_ : (α : Ord)  α < β  β  γ  α < γ
_<⟨_⟩suc_ = _<⟨_⟩_

_=⟨_⟩_ : (α : Ord)  α  β  β  γ  α  γ
α =⟨ α≡β  β≤γ = subst (_≤ _) (sym α≡β) β≤γ

_=˘⟨_⟩_ : (α : Ord)  β  α  β  γ  α  γ
α =˘⟨ β≡α  β≤γ = subst (_≤ _) β≡α β≤γ

_≤∎ :  α  α  α
_ ≤∎ = ≤-refl

Finally, α ≤ suc α (again by elimProp, the limit case using the reasoning combinators), and the two evident relations between α ≤ β and the successor.

≤s : α  suc α
≤s = elimProp  α  isProp≤ {α} {suc α}) z≤ s≤s
   {f} f≤sf  l≤ λ n 
    f [ n ]       ≤⟨ f≤sf n 
    suc (f [ n ]) ≤⟨ s≤s f≤l 
    suc (lim f)   ≤∎) _

s≤→≤ : suc α  β  α  β
s≤→≤ = ≤-trans ≤s

≤→≤s : α  β  α  suc β
≤→≤s α≤β = ≤-trans α≤β ≤s