The finite stages, and the order they carry

The previous chapter located, for each cell of a family, the one stage at which the cell first has a member, and showed that this stage is a successor. Every member of the cell that appears exactly there is therefore a definable subset of one and the same set: a name written over a single stage. What is still missing is a way to compare those names, and comparison is what this chapter builds, at the bottom of the tower.

Two claims carry it. The first is that each stage indexed by a numeral is finite, in the precise sense given below: it comes with a finite list of sets that hits all of its members. The second is that a finite stage carries a well-order, obtained by comparing two of its members at the earliest point where they disagree, and giving the larger place to whichever of the two contains that point.

The second claim is the mathematical content, and it is a claim about finite sets in an essential way. Order the subsets of the natural numbers by that same recipe and there is an infinite descent: the set of all numbers, then all numbers from one on, then all from two on, and so forth, each step deleting the earliest surviving point and so landing strictly lower. Nothing about the recipe forbids this; what forbids it over a finite base is that a finite base has only finitely many subsets, so a search for a smallest one terminates. That is exactly how the well-foundedness proof below goes: a finite list plus a linear order yields a smallest member of any inhabited property, by scanning the list and keeping the best hit; and "every inhabited property has a smallest member" is, classically, well-foundedness.

The finiteness climbs the tower because the definable subsets of a finite set are all of its subsets, and a set with a list has only finitely many subsets, one for each vector of bits over that list. So a list of the stage yields a list of the next stage, and the recursion needs nothing else.

The limit stage is then assembled without any further work about how the finite orders sit inside one another, because they do not: comparison at the earliest disagreement does not extend from one stage to the next. The floor number is the primary key instead. Two members of the limit that first appear at different finite stages are compared by those stage numbers alone; two that first appear at the same stage are compared by that stage's own order. Nothing else is needed, and nothing else is true.

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

open import Base.Prelude
open import Base.Truth
open import Base.Classical using ( LEM )

module L.Choice.Finite { : Level} (lem : LEM (ℓ-suc )) where

open import FOL.ZFStructure using ( module hPropStructure )
open import V.Hierarchy {} using ( 𝒮ᵥ; extensionalV )
open import L.Constructible {} using ( IsOrd; Lset; Lset-out; 𝒟ₒ; 𝒟ₒ∋⊆ )
open import L.Ordinal {} using ( numeral-ord )
open import L.Axioms.Basic {}
  using ( finSet; finSet-in; finSet-out; Lset-suc; module FinOf )
open import L.WellOrder.Base {ℓ-suc }
  using ( Tri; lt; eq; gt; SWO; IsLeast; leastOf )

open import Cubical.Data.Bool using ( Bool; true; false; false≢true )
open import Cubical.Data.Nat using ( _+_ )
open import Cubical.Data.Nat.Order using ( _<_; <-trans; ¬m<m; <-wellfounded; _≟_ )
import Cubical.Data.Nat.Order as NatOrder
open import Cubical.Data.Sigma using ( Σ≡Prop )
open import Cubical.Data.Sum using ( _⊎_; inl; inr )
import Cubical.Data.Empty as Empty
import Cubical.HITs.PropositionalTruncation as PT
open PT using ( ∣_∣₁; ∥_∥₁ )
open import Cubical.Functions.Logic using ( ⇔toPath )
open import Cubical.Induction.WellFounded
  using ( Acc; acc; WellFounded; isPropAcc; module WFI )
open import Cubical.Relation.Nullary using ( isProp¬ )
open import Cubical.HITs.CumulativeHierarchy.Properties
  using ( ∈∈ₛ; ∈-asFiber; ⟪_⟫; ⟪_⟫↪ )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( ; ∅-empty; module InfinitySet )
open InfinitySet using ( #_; ω )

open TruthAlgebra (hPropAlgebra (ℓ-suc ))
open hPropStructure 𝒮ᵥ

Tallies

Finiteness enters as a tally: a number, a family of that many sets all belonging to A, and the statement that every member of A is merely one of them. onto reads "the family hits everyone".

Nothing is asked about repetitions and nothing is asked about deciding equality: a tally is a surjection from a finite index, not a bijection. That is deliberate. The two uses ahead are a scan (which does not mind seeing an element twice) and a bit vector (which does not mind either), and asking for less means the tally of the next stage is cheaper to build. The whole finiteness vocabulary of this chapter is this record plus the index arithmetic that builds one tally out of another.

record Tally (A : S) : Type (ℓ-suc ) where
  field
    size   : 
    item   : Fin size  S
    inside : (i : Fin size)   item i ∈ˢ A 
    onto   : (x : S)   x ∈ˢ A    Σ[ i  Fin size ] (item i  x) ∥₁

Splitting a finite index

Tallying a power set means enumerating bit vectors, and there are twice as many vectors of length n + 1 as of length n. So one piece of index arithmetic is needed: an index below a + b is either an index below a or an index below b, and conversely. Only one of the two round trips is ever used, so only that one is proved; bumpLeft is the shift that makes the recursion on a type-check.

bumpLeft : {a b : }  Fin a  Fin b  Fin (suc a)  Fin b
bumpLeft (inl i) = inl (suc i)
bumpLeft (inr j) = inr j

joinFin : (a : ) {b : }  Fin a  Fin b  Fin (a + b)
joinFin zero    (inr j)       = j
joinFin (suc a) (inl zero)    = zero
joinFin (suc a) (inl (suc i)) = suc (joinFin a (inl i))
joinFin (suc a) (inr j)       = suc (joinFin a (inr j))

splitFin : (a : ) {b : }  Fin (a + b)  Fin a  Fin b
splitFin zero    j       = inr j
splitFin (suc a) zero    = inl zero
splitFin (suc a) (suc i) = bumpLeft (splitFin a i)

split-join : (a : ) {b : } (x : Fin a  Fin b)  splitFin a (joinFin a x)  x
split-join zero    (inr j)       = refl
split-join (suc a) (inl zero)    = refl
split-join (suc a) (inl (suc i)) = cong bumpLeft (split-join a (inl i))
split-join (suc a) (inr j)       = cong bumpLeft (split-join a (inr j))

Enumerating the masks

A mask of length n is a vector of n bits; it will say, of a tallied set, which entries to keep. There are maskCount n of them, that number being two to the n written as an iterated doubling, and maskAt reads an index as a mask: split the index in half, and the half it lands in supplies the leading bit while the rest supplies the tail. Every mask is read off some index, which is mask-onto, and that is the only property of the enumeration anyone needs. It is not injective on the nose and does not have to be.

maskCount :   
maskCount zero    = 1
maskCount (suc n) = maskCount n + maskCount n

maskCons : (n : )  (Fin (maskCount n)  Vec Bool n)
          Fin (maskCount n)  Fin (maskCount n)  Vec Bool (suc n)
maskCons n r (inl j) = false  r j
maskCons n r (inr j) = true   r j

maskAt : (n : )  Fin (maskCount n)  Vec Bool n
maskAt zero    j = []
maskAt (suc n) j = maskCons n (maskAt n) (splitFin (maskCount n) j)

mask-onto : (n : ) (v : Vec Bool n)  Σ[ j  Fin (maskCount n) ] (maskAt n j  v)
mask-onto zero    []          = zero , refl
mask-onto (suc n) (false  v) =
  joinFin (maskCount n) (inl (mask-onto n v .fst))
  , (cong (maskCons n (maskAt n)) (split-join (maskCount n) (inl (mask-onto n v .fst)))
      cong (false ∷_) (mask-onto n v .snd))
mask-onto (suc n) (true  v)  =
  joinFin (maskCount n) (inr (mask-onto n v .fst))
  , (cong (maskCons n (maskAt n)) (split-join (maskCount n) (inr (mask-onto n v .fst)))
      cong (true ∷_) (mask-onto n v .snd))

Selecting a sub-family

select applies a mask to a family: it keeps the entries whose bit is true and returns them as a family again, together with its own length. The length is produced by the recursion, which is the point: nothing has to be counted, and no arithmetic relates the answer to the mask.

Two specifications say what the result contains, and both are untruncated, because each is read straight off the same recursion. marks runs in the other direction, turning a decision on the entries into the mask that records it.

selectStep : {ℓ' : Level} {X : Type ℓ'}  X  Σ[ k   ] (Fin k  X)
            Σ[ k   ] (Fin k  X)
selectStep {X = X} x (k , g) = suc k , h
  where
  h : Fin (suc k)  X
  h zero    = x
  h (suc i) = g i

select : {ℓ' : Level} {X : Type ℓ'} (n : )  (Fin n  X)  Vec Bool n
        Σ[ k   ] (Fin k  X)
select zero    f v           = zero , λ ()
select (suc n) f (false  v) = select n  i  f (suc i)) v
select (suc n) f (true  v)  = selectStep (f zero) (select n  i  f (suc i)) v)

select-out : {ℓ' : Level} {X : Type ℓ'} (n : ) (f : Fin n  X) (v : Vec Bool n)
             (j : Fin (select n f v .fst))
            Σ[ i  Fin n ] ((lookup i v  true) × (select n f v .snd j  f i))
select-out zero    f []          ()
select-out (suc n) f (false  v) j       = step (select-out n  i  f (suc i)) v j)
  where
  step : Σ[ i  Fin n ] ((lookup i v  true)
           × (select n  i  f (suc i)) v .snd j  f (suc i)))
        Σ[ i  Fin (suc n) ] ((lookup i (false  v)  true)
           × (select (suc n) f (false  v) .snd j  f i))
  step (i , e , q) = suc i , (e , q)
select-out (suc n) f (true  v)  zero    = zero , (refl , refl)
select-out (suc n) f (true  v)  (suc j) = step (select-out n  i  f (suc i)) v j)
  where
  step : Σ[ i  Fin n ] ((lookup i v  true)
           × (select n  i  f (suc i)) v .snd j  f (suc i)))
        Σ[ i  Fin (suc n) ] ((lookup i (true  v)  true)
           × (select (suc n) f (true  v) .snd (suc j)  f i))
  step (i , e , q) = suc i , (e , q)

select-in : {ℓ' : Level} {X : Type ℓ'} (n : ) (f : Fin n  X) (v : Vec Bool n)
            (i : Fin n)  lookup i v  true
           Σ[ j  Fin (select n f v .fst) ] (select n f v .snd j  f i)
select-in zero    f []          ()      e
select-in (suc n) f (false  v) zero    e = Empty.rec (false≢true e)
select-in (suc n) f (false  v) (suc i) e = select-in n  i  f (suc i)) v i e
select-in (suc n) f (true  v)  zero    e = zero , refl
select-in (suc n) f (true  v)  (suc i) e = step (select-in n  i  f (suc i)) v i e)
  where
  step : Σ[ j  Fin (select n  i  f (suc i)) v .fst) ]
           (select n  i  f (suc i)) v .snd j  f (suc i))
        Σ[ j  Fin (select (suc n) f (true  v) .fst) ]
           (select (suc n) f (true  v) .snd j  f (suc i))
  step (j , q) = suc j , q

marks : {ℓ' : Level} {X : Type ℓ'} (n : )  (Fin n  X)  (X  Bool)  Vec Bool n
marks zero    f d = []
marks (suc n) f d = d (f zero)  marks n  i  f (suc i)) d

marks-lookup : {ℓ' : Level} {X : Type ℓ'} (n : ) (f : Fin n  X) (d : X  Bool)
               (i : Fin n)  lookup i (marks n f d)  d (f i)
marks-lookup (suc n) f d zero    = refl
marks-lookup (suc n) f d (suc i) = marks-lookup n  i  f (suc i)) d i

A truth value, decided into a bit

The excluded middle hands over a disjunction, and a mask wants a bit, so the two have to be introduced to each other. The verdict is taken as an argument rather than looked up inside the definition: that is what lets the two round-trip lemmas be proved by matching on it, with the truth value itself given explicitly, since an implicit argument buried under ⟨_⟩ is never inferred.

decideOf : (P : Ω)  ( P   ( P   Empty.⊥))  Bool
decideOf P (inl _) = true
decideOf P (inr _) = false

decide-true : (P : Ω) (s :  P   ( P   Empty.⊥))   P   decideOf P s  true
decide-true P (inl _)  p = refl
decide-true P (inr np) p = Empty.rec (np p)

decide-sound : (P : Ω) (s :  P   ( P   Empty.⊥))  decideOf P s  true   P 
decide-sound P (inl p) _ = p
decide-sound P (inr _) e = Empty.rec (false≢true e)

The definable subsets of a tallied stage

Here is the step that makes finiteness climb. Fix an ordinal σ and a tally of the stage Lset σ. Each entry of the tally is a member of that stage, so each has a name in the stage's small member type, which is what the basic-axioms chapter's finite disjunction wants; part applies a mask to those names and takes the finite set they span. That set is a definable subset of the stage, for the reason recorded there: the finite disjunction of "equals this one" carves it out.

Two specifications relate membership in part v to the mask, in each direction. Then the converse: given any definable subset x, mark each entry of the tally according to whether it belongs to x, and part of that mask is x. One direction is immediate from the specification; the other needs that x stays inside the stage, so that every member of x is hit by the tally in the first place. So the masks tally the definable subsets, and a tally of a stage yields a tally of the next.

module PowerStep (σ : S) ( : IsOrd σ) (t : Tally (Lset σ)) where
  open Tally t
  open FinOf σ  using ( finSet∈𝒟ₒ )

  index : Fin size   Lset σ 
  index i = ∈-asFiber {a = item i} {b = Lset σ} (inside i) .fst

  index-eq : (i : Fin size)   Lset σ ⟫↪ (index i)  item i
  index-eq i = ∈-asFiber {a = item i} {b = Lset σ} (inside i) .snd

  chosen : Vec Bool size  Σ[ k   ] (Fin k   Lset σ )
  chosen v = select size index v

  part : Vec Bool size  S
  part v = finSet (chosen v .fst)  j   Lset σ ⟫↪ (chosen v .snd j))

  part-def : (v : Vec Bool size)   part v ∈ˢ 𝒟ₒ (Lset σ) 
  part-def v = finSet∈𝒟ₒ (chosen v .fst) (chosen v .snd)

  part-out : (v : Vec Bool size) (y : S)   y ∈ˢ part v 
             Σ[ i  Fin size ] ((lookup i v  true) × (item i  y)) ∥₁
  part-out v y y∈ = PT.map step
    (finSet-out (chosen v .fst)  j   Lset σ ⟫↪ (chosen v .snd j)) y y∈)
    where
    step : Σ[ j  Fin (chosen v .fst) ] ( Lset σ ⟫↪ (chosen v .snd j)  y)
          Σ[ i  Fin size ] ((lookup i v  true) × (item i  y))
    step (j , q) = out .fst
                 , ( out .snd .fst
                   , (sym (index-eq (out .fst))
                       cong  Lset σ ⟫↪ (sym (out .snd .snd))  q) )
      where
      out : Σ[ i  Fin size ] ((lookup i v  true) × (chosen v .snd j  index i))
      out = select-out size index v j

  part-mem : (v : Vec Bool size) (i : Fin size)  lookup i v  true
             item i ∈ˢ part v 
  part-mem v i e = subst  w   w ∈ˢ part v ) path
    (finSet-in (chosen v .fst)  j   Lset σ ⟫↪ (chosen v .snd j))
      ( Lset σ ⟫↪ (chosen v .snd (ins .fst)))  ins .fst , refl ∣₁)
    where
    ins : Σ[ j  Fin (chosen v .fst) ] (chosen v .snd j  index i)
    ins = select-in size index v i e
    path :  Lset σ ⟫↪ (chosen v .snd (ins .fst))  item i
    path = cong  Lset σ ⟫↪ (ins .snd)  index-eq i

  maskOf : S  Vec Bool size
  maskOf x = marks size item  y  decideOf (y ∈ˢ x) (lem (y ∈ˢ x)))

  part-mask : (x : S)   x ∈ˢ 𝒟ₒ (Lset σ)   part (maskOf x)  x
  part-mask x x∈ = extensionalV  y  ⇔toPath (fwd y) (bwd y))
    where
    fwd : (y : S)   y ∈ˢ part (maskOf x)    y ∈ˢ x 
    fwd y y∈ = PT.rec (snd (y ∈ˢ x)) step (part-out (maskOf x) y y∈)
      where
      step : Σ[ i  Fin size ] ((lookup i (maskOf x)  true) × (item i  y))
             y ∈ˢ x 
      step (i , e , q) = subst  w   w ∈ˢ x ) q
        (decide-sound (item i ∈ˢ x) (lem (item i ∈ˢ x))
          (sym (marks-lookup size item
                  z  decideOf (z ∈ˢ x) (lem (z ∈ˢ x))) i)  e))
    bwd : (y : S)   y ∈ˢ x    y ∈ˢ part (maskOf x) 
    bwd y y∈x = PT.rec (snd (y ∈ˢ part (maskOf x))) step
      (onto y (𝒟ₒ∋⊆ (Lset σ) x x∈ y y∈x))
      where
      step : Σ[ i  Fin size ] (item i  y)   y ∈ˢ part (maskOf x) 
      step (i , q) = subst  w   w ∈ˢ part (maskOf x) ) q
        (part-mem (maskOf x) i
          (marks-lookup size item  z  decideOf (z ∈ˢ x) (lem (z ∈ˢ x))) i
            decide-true (item i ∈ˢ x) (lem (item i ∈ˢ x))
               (subst  w   w ∈ˢ x ) (sym q) y∈x)))

  powerTally : Tally (𝒟ₒ (Lset σ))
  powerTally = record
    { size   = maskCount size
    ; item   = λ j  part (maskAt size j)
    ; inside = λ j  part-def (maskAt size j)
    ; onto   = cover }
    where
    cover : (x : S)   x ∈ˢ 𝒟ₒ (Lset σ) 
            Σ[ j  Fin (maskCount size) ] (part (maskAt size j)  x) ∥₁
    cover x x∈ =  mask-onto size (maskOf x) .fst
                 , (cong part (mask-onto size (maskOf x) .snd)  part-mask x x∈) ∣₁

Smallest elements, and well-foundedness

Now the half of the argument that uses the tally rather than building one. Fix a type with a relation that is trichotomous, irreflexive and transitive, that is, everything a strict well-order asks for except being well founded.

scan walks a finite family and returns either an entry that satisfies the predicate and is smallest among the entries that do, or the assurance that no entry satisfies it. It is a plain recursion on the length: at each step the excluded middle decides the predicate at the head, trichotomy compares the head with the best found so far, and the four combinations are the four clauses. Nothing is truncated anywhere, which matters, because the caller wants an actual element and not a mere existence.

Given a family that hits everyone, least upgrades this to a smallest element of any inhabited predicate over the whole type: the "no entry satisfies it" branch is refuted by the witness, whose fibre in the family the predicate would have to hit.

Well-foundedness follows, and this is where the finiteness is spent. Being accessible is a proposition, so the excluded middle decides it. If some element were not accessible, there would be a smallest inaccessible one; everything below it is then accessible, which makes it accessible after all. The contradiction is the proof.

module Search {A : Type (ℓ-suc )} (_≺_ : A  A  Type (ℓ-suc ))
              (tri : (a b : A)  Tri (a  b) (a  b) (b  a))
              (irr : (a : A)  a  a  Empty.⊥)
              (trans : (a b c : A)  a  b  b  c  a  c) where

  Least : (P : A  Ω)  A  Type (ℓ-suc )
  Least P m =  P m  × ((b : A)   P b   b  m  Empty.⊥)

  Found : (P : A  Ω) (n : ) (f : Fin n  A)  Type (ℓ-suc )
  Found P n f =
    (Σ[ i  Fin n ] ( P (f i)  × ((j : Fin n)   P (f j)   f j  f i  Empty.⊥)))
     ((i : Fin n)   P (f i)   Empty.⊥)

  scan : (P : A  Ω) (n : ) (f : Fin n  A)  Found P n f
  scan P zero    f = inr  ())
  scan P (suc n) f = combine (scan P n  i  f (suc i))) (lem (P (f zero)))
    where
    combine : Found P n  i  f (suc i))
             ( P (f zero)   ( P (f zero)   Empty.⊥))  Found P (suc n) f
    combine (inl (i , pi , mi)) (inl p₀) = decide (tri (f zero) (f (suc i)))
      where
      decide : Tri (f zero  f (suc i)) (f zero  f (suc i)) (f (suc i)  f zero)
              Found P (suc n) f
      decide (lt h) = inl (zero , (p₀ , minAt))
        where
        minAt : (j : Fin (suc n))   P (f j)   f j  f zero  Empty.⊥
        minAt zero    pj hj = irr (f zero) hj
        minAt (suc j) pj hj = mi j pj (trans (f (suc j)) (f zero) (f (suc i)) hj h)
      decide (eq h) = inl (suc i , (pi , minAt))
        where
        minAt : (j : Fin (suc n))   P (f j)   f j  f (suc i)  Empty.⊥
        minAt zero    pj hj = irr (f (suc i)) (subst  w  w  f (suc i)) h hj)
        minAt (suc j) pj hj = mi j pj hj
      decide (gt h) = inl (suc i , (pi , minAt))
        where
        minAt : (j : Fin (suc n))   P (f j)   f j  f (suc i)  Empty.⊥
        minAt zero    pj hj = irr (f (suc i)) (trans (f (suc i)) (f zero) (f (suc i)) h hj)
        minAt (suc j) pj hj = mi j pj hj
    combine (inl (i , pi , mi)) (inr n₀) = inl (suc i , (pi , minAt))
      where
      minAt : (j : Fin (suc n))   P (f j)   f j  f (suc i)  Empty.⊥
      minAt zero    pj hj = Empty.rec (n₀ pj)
      minAt (suc j) pj hj = mi j pj hj
    combine (inr none) (inl p₀) = inl (zero , (p₀ , minAt))
      where
      minAt : (j : Fin (suc n))   P (f j)   f j  f zero  Empty.⊥
      minAt zero    pj hj = irr (f zero) hj
      minAt (suc j) pj hj = Empty.rec (none j pj)
    combine (inr none) (inr n₀) = inr atAll
      where
      atAll : (i : Fin (suc n))   P (f i)   Empty.⊥
      atAll zero    p = n₀ p
      atAll (suc i) p = none i p

  module Over (n : ) (f : Fin n  A)
              (cov : (a : A)   Σ[ i  Fin n ] (f i  a) ∥₁) where

    least : (P : A  Ω)   Σ[ a  A ]  P a  ∥₁  Σ[ m  A ] Least P m
    least P h = decide (scan P n f)
      where
      nowhere : ((i : Fin n)   P (f i)   Empty.⊥)  Empty.⊥
      nowhere none = PT.rec Empty.isProp⊥ atWitness h
        where
        atWitness : Σ[ a  A ]  P a   Empty.⊥
        atWitness (a , pa) = PT.rec Empty.isProp⊥
           { (i , q)  none i (subst  w   P w ) (sym q) pa) }) (cov a)
      decide : Found P n f  Σ[ m  A ] Least P m
      decide (inl (i , pi , mi)) = f i , (pi , everywhere)
        where
        everywhere : (b : A)   P b   b  f i  Empty.⊥
        everywhere b pb hb = PT.rec Empty.isProp⊥
           { (j , q)  mi j (subst  w   P w ) (sym q) pb)
                              (subst  w  w  f i) (sym q) hb) }) (cov b)
      decide (inr none) = Empty.rec (nowhere none)

    wellFounded : WellFounded _≺_
    wellFounded a = fromDec (lem (Acc _≺_ a , isPropAcc a))
      where
      fromDec : (Acc _≺_ a  (Acc _≺_ a  Empty.⊥))  Acc _≺_ a
      fromDec (inl h) = h
      fromDec (inr nh) = Empty.rec (found .snd .fst (acc below))
        where
        NotAcc : A  Ω
        NotAcc b = (Acc _≺_ b  Empty.⊥) , isProp¬ _
        found : Σ[ m  A ] Least NotAcc m
        found = least NotAcc  a , nh ∣₁
        below : (b : A)  b  found .fst  Acc _≺_ b
        below b hb = pick (lem (Acc _≺_ b , isPropAcc b))
          where
          pick : (Acc _≺_ b  (Acc _≺_ b  Empty.⊥))  Acc _≺_ b
          pick (inl h)  = h
          pick (inr nb) = Empty.rec (found .snd .snd b nb hb)

The natural numbers, well-ordered

One order in this chapter is not finite, and it is the one that counts the floors. The library supplies everything about the usual order on the natural numbers, so the bundle is assembled rather than proved: the trichotomy is the library's decision procedure with its three-way answer renamed, and well-foundedness is the library's own.

The lift is bookkeeping and nothing more. A bundle carries its relation at a single universe level fixed once for the whole chapter, and the order on the natural numbers lives at the bottom, so it is raised to meet it. This is the first time the well-order chapter is exercised at all.

liftAcc : (n : )  Acc _<_ n  Acc  a b  Lift {ℓ-zero} {ℓ-suc } (a < b)) n
liftAcc n (acc r) = acc  m h  liftAcc m (r m (lower h)))

natOrder : SWO {ℓ-zero} 
natOrder = record
  { _<∙_   = λ a b  Lift (a < b)
  ; tri∙   = triOf
  ; irr∙   = λ a h  ¬m<m (lower h)
  ; trans∙ = λ a b c h k  lift (<-trans (lower h) (lower k))
  ; wf∙    = λ n  liftAcc n (<-wellfounded n) }
  where
  triOf : (a b : )  Tri (Lift (a < b)) (a  b) (Lift (b < a))
  triOf a b = fromNat (a  b)
    where
    fromNat : NatOrder.Trichotomy a b  Tri (Lift (a < b)) (a  b) (Lift (b < a))
    fromNat (NatOrder.lt h) = lt (lift h)
    fromNat (NatOrder.eq h) = eq h
    fromNat (NatOrder.gt h) = gt (lift h)

The earliest disagreement

Fix a set A and a relation R on sets, to be read as an order on the members of A. Two subsets of A are compared by looking at where they disagree. A witness that x comes before y is a member z of A that belongs to y and not to x, such that x and y agree below z, meaning that every member of A that R puts before z belongs to one exactly when it belongs to the other. Read backwards: z is the earliest point of disagreement, and y is the one that has it.

Irreflexivity is immediate and needs no hypothesis at all: a witness for x against itself would belong to x and not belong to x.

Agrees : (R : S  S  Ω) (A x y z : S)  Type (ℓ-suc )
Agrees R A x y z = (w : S)   w ∈ˢ A    R w z 
                  ( w ∈ˢ x    w ∈ˢ y ) × ( w ∈ˢ y    w ∈ˢ x )

Witness : (R : S  S  Ω) (A x y z : S)  Type (ℓ-suc )
Witness R A x y z =
   z ∈ˢ A  ×  z ∈ˢ y  × ( z ∈ˢ x   Empty.⊥) × Agrees R A x y z

precedes : (R : S  S  Ω) (A : S)  S  S  Ω
precedes R A x y =  Σ[ z  S ] Witness R A x y z ∥₁ , PT.squash₁

precedes-irrefl : (R : S  S  Ω) (A x : S)   precedes R A x x   Empty.⊥
precedes-irrefl R A x = PT.rec Empty.isProp⊥  { (z , _ , z∈ , z∉ , _)  z∉ z∈ })

Transitivity and trichotomy do need hypotheses on the base order, and the two need different ones, so both are collected in one module: trichotomy and transitivity of R on the members of A, and the smallest-element principle for R over those members. In the tower these come from the stage below.

Transitivity is a comparison of two witnesses. If x comes before y at p and y comes before z at q, then p and q cannot be equal, since p belongs to y and q does not; and whichever of the two is smaller witnesses that x comes before z. Both branches check the same two things: that the smaller point is on the right side, and that the agreement below it composes.

module Difference (R : S  S  Ω) (A : S)
  (baseTri : (a b : S)   a ∈ˢ A    b ∈ˢ A   Tri  R a b  (a  b)  R b a )
  (baseTrans : (a b c : S)   R a b    R b c    R a c )
  (baseLeast : (P : S  Ω)   Σ[ a  S ] ( a ∈ˢ A  ×  P a ) ∥₁
              Σ[ m  S ] ( m ∈ˢ A  ×  P m 
                 × ((b : S)   b ∈ˢ A    P b    R b m   Empty.⊥)))
  where

  precedes-trans : (x y z : S)   precedes R A x y    precedes R A y z 
                   precedes R A x z 
  precedes-trans x y z hxy hyz =
    PT.rec PT.squash₁  wp  PT.rec PT.squash₁ (both wp) hyz) hxy
    where
    both : Σ[ p  S ] Witness R A x y p  Σ[ q  S ] Witness R A y z q
           precedes R A x z 
    both (p , p∈A , p∈y , p∉x , agp) (q , q∈A , q∈z , q∉y , agq) =
      decide (baseTri p q p∈A q∈A)
      where
      decide : Tri  R p q  (p  q)  R q p    precedes R A x z 
      decide (lt h) =  p , (p∈A , (agq p p∈A h .fst p∈y , (p∉x , ag))) ∣₁
        where
        ag : Agrees R A x z p
        ag w w∈A hw =
             wx  agq w w∈A (baseTrans w p q hw h) .fst (agp w w∈A hw .fst wx))
          ,  wz  agp w w∈A hw .snd (agq w w∈A (baseTrans w p q hw h) .snd wz))
      decide (eq h) = Empty.rec (q∉y (subst  v   v ∈ˢ y ) h p∈y))
      decide (gt h) =  q , (q∈A , (q∈z , (q∉x , ag))) ∣₁
        where
        q∉x :  q ∈ˢ x   Empty.⊥
        q∉x qx = q∉y (agp q q∈A h .fst qx)
        ag : Agrees R A x z q
        ag w w∈A hw =
             wx  agq w w∈A hw .fst (agp w w∈A (baseTrans w q p hw h) .fst wx))
          ,  wz  agp w w∈A (baseTrans w q p hw h) .snd (agq w w∈A hw .snd wz))

Trichotomy is where the excluded middle and the smallest-element principle are spent. Ask whether the two subsets disagree anywhere in A. If they do not, they agree everywhere in A; since both stay inside A, they agree everywhere at all, and extensionality identifies them. If they do, there is an earliest point of disagreement, and one further decision, whether that point belongs to the first subset, says which way the comparison goes. Agreement below the point is free in both branches: nothing below it disagrees, by the choice of the point.

The excluded middle is used a second time inside agree, to turn "not disagreeing" into "agreeing"; that step is exactly a double negation and cannot be had for less.

  precedes-tri : (x y : S)  ((w : S)   w ∈ˢ x    w ∈ˢ A )
                            ((w : S)   w ∈ˢ y    w ∈ˢ A )
                Tri  precedes R A x y  (x  y)  precedes R A y x 
  precedes-tri x y x⊆ y⊆ = decide (lem (Some , PT.squash₁))
    where
    Apart : S  Ω
    Apart w =  ( w ∈ˢ x  × ( w ∈ˢ y   Empty.⊥))
               (( w ∈ˢ x   Empty.⊥) ×  w ∈ˢ y ) ∥₁ , PT.squash₁
    Some : Type (ℓ-suc )
    Some =  Σ[ a  S ] ( a ∈ˢ A  ×  Apart a ) ∥₁
    agree : (w : S)  ( Apart w   Empty.⊥)
           ( w ∈ˢ x    w ∈ˢ y ) × ( w ∈ˢ y    w ∈ˢ x )
    agree w na = fwd , bwd
      where
      fwd :  w ∈ˢ x    w ∈ˢ y 
      fwd wx = pick (lem (w ∈ˢ y))
        where
        pick : ( w ∈ˢ y   ( w ∈ˢ y   Empty.⊥))   w ∈ˢ y 
        pick (inl h)  = h
        pick (inr nh) = Empty.rec (na  inl (wx , nh) ∣₁)
      bwd :  w ∈ˢ y    w ∈ˢ x 
      bwd wy = pick (lem (w ∈ˢ x))
        where
        pick : ( w ∈ˢ x   ( w ∈ˢ x   Empty.⊥))   w ∈ˢ x 
        pick (inl h)  = h
        pick (inr nh) = Empty.rec (na  inr (nh , wy) ∣₁)
    same : (Some  Empty.⊥)  x  y
    same ns = extensionalV step
      where
      nApart : (w : S)   Apart w   Empty.⊥
      nApart w ha = ns  w , (inA , ha) ∣₁
        where
        inA :  w ∈ˢ A 
        inA = PT.rec (snd (w ∈ˢ A))
           { (inl (wx , _))  x⊆ w wx ; (inr (_ , wy))  y⊆ w wy }) ha
      step : (w : S)  (w ∈ˢ x)  (w ∈ˢ y)
      step w = ⇔toPath (agree w (nApart w) .fst) (agree w (nApart w) .snd)
    decide : (Some  (Some  Empty.⊥))
            Tri  precedes R A x y  (x  y)  precedes R A y x 
    decide (inr ns) = eq (same ns)
    decide (inl hs) = side (lem (m ∈ˢ x))
      where
      found : Σ[ m  S ] ( m ∈ˢ A  ×  Apart m 
                × ((b : S)   b ∈ˢ A    Apart b    R b m   Empty.⊥))
      found = baseLeast Apart hs
      m : S
      m = found .fst
      m∈A :  m ∈ˢ A 
      m∈A = found .snd .fst
      apartM :  Apart m 
      apartM = found .snd .snd .fst
      belowM : (w : S)   w ∈ˢ A    R w m    Apart w   Empty.⊥
      belowM w w∈A hw ha = found .snd .snd .snd w w∈A ha hw
      side : ( m ∈ˢ x   ( m ∈ˢ x   Empty.⊥))
            Tri  precedes R A x y  (x  y)  precedes R A y x 
      side (inl mx) = gt  m , (m∈A , (mx , (m∉y , ag))) ∣₁
        where
        m∉y :  m ∈ˢ y   Empty.⊥
        m∉y my = PT.rec Empty.isProp⊥
           { (inl (_ , nmy))  nmy my ; (inr (nmx , _))  nmx mx }) apartM
        ag : Agrees R A y x m
        ag w w∈A hw = agree w (belowM w w∈A hw) .snd , agree w (belowM w w∈A hw) .fst
      side (inr nmx) = lt  m , (m∈A , (my , (nmx , ag))) ∣₁
        where
        my :  m ∈ˢ y 
        my = PT.rec (snd (m ∈ˢ y))
           { (inl (mx , _))  Empty.rec (nmx mx) ; (inr (_ , h))  h }) apartM
        ag : Agrees R A x y m
        ag w w∈A hw = agree w (belowM w w∈A hw)

The finite stages

The stages indexed by numerals are the finite ones, and the order on each is built by recursion: stage zero is empty, and the order on the stage after n is comparison at the earliest disagreement over stage n, with stage n's own order as the base. before-irrefl holds at every stage and needs no induction, since irreflexivity of the comparison needed no hypothesis and stage zero carries no comparison at all.

Tri-map : {ℓ₁ ℓ₂ ℓ₃ ℓ₄ ℓ₅ ℓ₆ : Level}
          {A₁ : Type ℓ₁} {B₁ : Type ℓ₂} {C₁ : Type ℓ₃}
          {A₂ : Type ℓ₄} {B₂ : Type ℓ₅} {C₂ : Type ℓ₆}
         (A₁  A₂)  (B₁  B₂)  (C₁  C₂)  Tri A₁ B₁ C₁  Tri A₂ B₂ C₂
Tri-map f g h (lt a) = lt (f a)
Tri-map f g h (eq b) = eq (g b)
Tri-map f g h (gt c) = gt (h c)

finiteStage :   S
finiteStage n = Lset (# n)

before :   S  S  Ω
before zero    x y = 
before (suc n) = precedes (before n) (finiteStage n)

before-irrefl : (n : ) (x : S)   before n x x   Empty.⊥
before-irrefl zero    x h = Empty.rec* h
before-irrefl (suc n) x h = precedes-irrefl (before n) (finiteStage n) x h

zero-empty : (x : S)   x ∈ˢ finiteStage zero   Empty.⊥
zero-empty x h = PT.rec Empty.isProp⊥ step (Lset-out (# zero) x h)
  where
  step : Σ[ δ  S ] ( δ ∈ˢ   ×  x ∈ˢ 𝒟ₒ (Lset δ) )  Empty.⊥
  step (δ , δ∈ , _) = ∅-empty δ (∈∈ₛ {a = δ} {b = } .fst δ∈)

What the recursion has to carry is a tally, trichotomy and transitivity, and nothing else: irreflexivity is free at every stage, and well-foundedness is derived where it is used rather than transported. A point of a stage is a set together with its membership, which is a proposition, so two points are equal as soon as their sets are; that is the only bookkeeping in passing between the statements about sets and the bundle, whose carrier must be a type.

Point :   Type (ℓ-suc )
Point n = Σ[ x  S ]  x ∈ˢ finiteStage n 

Below : (n : )  Point n  Point n  Type (ℓ-suc )
Below n a b =  before n (a .fst) (b .fst) 

record StageOrder (n : ) : Type (ℓ-suc ) where
  field
    tally : Tally (finiteStage n)
    tri   : (x y : S)   x ∈ˢ finiteStage n    y ∈ˢ finiteStage n 
           Tri  before n x y  (x  y)  before n y x 
    trans : (x y z : S)   before n x y    before n y z    before n x z 

module Ordered (n : ) (r : StageOrder n) where
  open StageOrder r public
  open Tally tally

  triPoint : (a b : Point n)  Tri (Below n a b) (a  b) (Below n b a)
  triPoint a b = Tri-map id (Σ≡Prop  z  snd (z ∈ˢ finiteStage n))) id
    (tri (a .fst) (b .fst) (a .snd) (b .snd))

  points : Fin size  Point n
  points i = item i , inside i

  covers : (a : Point n)   Σ[ i  Fin size ] (points i  a) ∥₁
  covers a = PT.map  { (i , q)  i , Σ≡Prop  z  snd (z ∈ˢ finiteStage n)) q })
    (onto (a .fst) (a .snd))

  open Search (Below n) triPoint  a  before-irrefl n (a .fst))
               a b c  trans (a .fst) (b .fst) (c .fst)) public
  open Over size points covers public

  order : SWO (Point n)
  order = record
    { _<∙_   = Below n
    ; tri∙   = triPoint
    ; irr∙   = λ a  before-irrefl n (a .fst)
    ; trans∙ = λ a b c  trans (a .fst) (b .fst) (c .fst)
    ; wf∙    = wellFounded }

  leastMem : (P : S  Ω)   Σ[ a  S ] ( a ∈ˢ finiteStage n  ×  P a ) ∥₁
            Σ[ m  S ] ( m ∈ˢ finiteStage n  ×  P m 
               × ((b : S)   b ∈ˢ finiteStage n    P b 
                            before n b m   Empty.⊥))
  leastMem P h = found .fst .fst
               , ( found .fst .snd
                 , ( found .snd .fst
                   ,  b b∈ pb hb  found .snd .snd (b , b∈) pb hb) ) )
    where
    Q : Point n  Ω
    Q a = P (a .fst)
    found : Σ[ m  Point n ] Least Q m
    found = least Q (PT.map  { (a , a∈ , pa)  (a , a∈) , pa }) h)

And the recursion itself. At zero everything is discharged by the stage being empty. At a successor the tally is the previous stage's tally raised through the definable power set, and the two order facts are the two theorems about the earliest disagreement, applied with the previous stage supplying its trichotomy, its transitivity and its smallest elements. The identification of a successor stage with the definable power set below it is used three times, once per field, and each time only to move a membership statement across it.

stageOrder : (n : )  StageOrder n
stageOrder zero = record { tally = empty ; tri = triZero ; trans = transZero }
  where
  empty : Tally (finiteStage zero)
  empty = record
    { size   = zero
    ; item   = λ ()
    ; inside = λ ()
    ; onto   = λ x x∈  Empty.rec (zero-empty x x∈) }
  triZero : (x y : S)   x ∈ˢ finiteStage zero    y ∈ˢ finiteStage zero 
           Tri  before zero x y  (x  y)  before zero y x 
  triZero x y x∈ y∈ = Empty.rec (zero-empty x x∈)
  transZero : (x y z : S)   before zero x y    before zero y z 
              before zero x z 
  transZero x y z h k = Empty.rec* h
stageOrder (suc n) = record { tally = raised ; tri = triSuc ; trans = transSuc }
  where
  module Prev = Ordered n (stageOrder n)
  module Diff = Difference (before n) (finiteStage n) Prev.tri Prev.trans Prev.leastMem
  module Power = PowerStep (# n) (numeral-ord n) Prev.tally

  step : finiteStage (suc n)  𝒟ₒ (finiteStage n)
  step = Lset-suc (# n)

  raised : Tally (finiteStage (suc n))
  raised = record
    { size   = Tally.size Power.powerTally
    ; item   = Tally.item Power.powerTally
    ; inside = λ i  subst  w   Tally.item Power.powerTally i ∈ˢ w ) (sym step)
                       (Tally.inside Power.powerTally i)
    ; onto   = λ x x∈  Tally.onto Power.powerTally x
                          (subst  w   x ∈ˢ w ) step x∈) }

  members : (x : S)   x ∈ˢ finiteStage (suc n) 
           (w : S)   w ∈ˢ x    w ∈ˢ finiteStage n 
  members x x∈ = 𝒟ₒ∋⊆ (finiteStage n) x (subst  v   x ∈ˢ v ) step x∈)

  triSuc : (x y : S)   x ∈ˢ finiteStage (suc n)    y ∈ˢ finiteStage (suc n) 
          Tri  before (suc n) x y  (x  y)  before (suc n) y x 
  triSuc x y x∈ y∈ = Diff.precedes-tri x y (members x x∈) (members y y∈)

  transSuc : (x y z : S)   before (suc n) x y    before (suc n) y z 
             before (suc n) x z 
  transSuc = Diff.precedes-trans

The limit stage

A member of the limit stage appears at some finite stage, since the limit is the union of the stages below it and each of those is indexed by a numeral. Among the numerals at which it has appeared there is a smallest, and that number is its level. This is the one place where the well-order of the natural numbers is spent, and the smallest-element theorem of the well-order chapter is what spends it.

Limit : Type (ℓ-suc )
Limit = Σ[ x  S ]  x ∈ˢ Lset ω 

inSome : (x : S)   x ∈ˢ Lset ω    Σ[ n   ]  x ∈ˢ finiteStage n  ∥₁
inSome x h = PT.rec PT.squash₁ atStage (Lset-out ω x h)
  where
  atStage : Σ[ δ  S ] ( δ ∈ˢ ω  ×  x ∈ˢ 𝒟ₒ (Lset δ) )
            Σ[ n   ]  x ∈ˢ finiteStage n  ∥₁
  atStage (δ , δ∈ω , x∈) = PT.map named δ∈ω
    where
    named : Σ[ k  Lift  ] (# (lower k)  δ)  Σ[ n   ]  x ∈ˢ finiteStage n 
    named (k , q) = suc (lower k)
      , subst  w   x ∈ˢ w ) (sym (Lset-suc (# (lower k))))
          (subst  w   x ∈ˢ 𝒟ₒ (Lset w) ) (sym q) x∈)

levelData : (a : Limit)
           Σ[ n   ] IsLeast natOrder  m  a .fst ∈ˢ finiteStage m) n
levelData a =
  leastOf natOrder lem  m  a .fst ∈ˢ finiteStage m) (inSome (a .fst) (a .snd))

level : Limit  
level a = levelData a .fst

level-in : (a : Limit)   a .fst ∈ˢ finiteStage (level a) 
level-in a = levelData a .snd .fst

The order on the limit takes the level as the primary key: a member of a lower level comes first, and two members of the same level are compared by that level's own order. The equation between levels is carried in the second alternative, and carried in the direction that lets the second member be read at the first's level, which is what keeps the definition free of any transport.

Irreflexivity and transitivity are case analyses on that alternative, with the level equations moving the stage-order facts to the level where they are needed. Trichotomy compares levels first and defers to the stage only when they agree.

_≺_ : Limit  Limit  Type (ℓ-suc )
a  b = Lift {ℓ-zero} {ℓ-suc } (level a < level b)
       ((level b  level a) ×  before (level a) (a .fst) (b .fst) )

limit-irrefl : (a : Limit)  a  a  Empty.⊥
limit-irrefl a (inl h)       = ¬m<m (lower h)
limit-irrefl a (inr (_ , h)) = before-irrefl (level a) (a .fst) h

limit-trans : (a b c : Limit)  a  b  b  c  a  c
limit-trans a b c (inl h)       (inl k)       = inl (lift (<-trans (lower h) (lower k)))
limit-trans a b c (inl h)       (inr (q , _)) =
  inl (lift (subst  j  level a < j) (sym q) (lower h)))
limit-trans a b c (inr (q , _)) (inl k)       =
  inl (lift (subst  j  j < level c) q (lower k)))
limit-trans a b c (inr (q , hab)) (inr (p , hbc)) = inr (p  q , joined)
  where
  moved :  before (level a) (b .fst) (c .fst) 
  moved = subst  j   before j (b .fst) (c .fst) ) q hbc
  joined :  before (level a) (a .fst) (c .fst) 
  joined = StageOrder.trans (stageOrder (level a)) (a .fst) (b .fst) (c .fst) hab moved

limit-tri : (a b : Limit)  Tri (a  b) (a  b) (b  a)
limit-tri a b = byLevel (level a  level b)
  where
  byLevel : NatOrder.Trichotomy (level a) (level b)  Tri (a  b) (a  b) (b  a)
  byLevel (NatOrder.lt h) = lt (inl (lift h))
  byLevel (NatOrder.gt h) = gt (inl (lift h))
  byLevel (NatOrder.eq p) = same
    (StageOrder.tri (stageOrder (level a)) (a .fst) (b .fst) (level-in a) b∈)
    where
    b∈ :  b .fst ∈ˢ finiteStage (level a) 
    b∈ = subst  j   b .fst ∈ˢ finiteStage j ) (sym p) (level-in b)
    same : Tri  before (level a) (a .fst) (b .fst)  (a .fst  b .fst)
                before (level a) (b .fst) (a .fst) 
          Tri (a  b) (a  b) (b  a)
    same (lt h) = lt (inr (sym p , h))
    same (eq q) = eq (Σ≡Prop  z  snd (z ∈ˢ Lset ω)) q)
    same (gt h) = gt (inr (p , subst  j   before j (b .fst) (a .fst) ) p h))

Well-foundedness is two nested inductions, and they are kept apart on purpose. The outer one is induction on the level, in the library's packaged form, and it hands down a hypothesis covering every lower level. The inner one is an ordinary descent along the accessibility that the finite stage already has, which is legitimate precisely because that stage is finite. A step down in level appeals to the outer hypothesis; a step within a level appeals to the inner one; and since the inner function recurses on nothing but its own accessibility argument, the two never have to be compared.

accInside : (k : )
           ((m : )  m < k  (b : Limit)  level b  m  Acc _≺_ b)
           (u : Point k)  Acc (Below k) u
           (b : Limit)  level b  k  b .fst  u .fst  Acc _≺_ b
accInside k ih u (acc ru) b q e = acc step
  where
  step : (c : Limit)  c  b  Acc _≺_ c
  step c (inl h) = ih (level c) (subst  j  level c < j) q (lower h)) c refl
  step c (inr (qb , hc)) = accInside k ih pc (ru pc below) c qc refl
    where
    qc : level c  k
    qc = sym qb  q
    pc : Point k
    pc = c .fst , subst  j   c .fst ∈ˢ finiteStage j ) qc (level-in c)
    below : Below k pc u
    below = subst  v   before k (c .fst) v ) e
              (subst  j   before j (c .fst) (b .fst) ) qc hc)

accByLevel : (k : )  (b : Limit)  level b  k  Acc _≺_ b
accByLevel = WFI.induction <-wellfounded outer
  where
  outer : (k : )  ((m : )  m < k  (b : Limit)  level b  m  Acc _≺_ b)
         (b : Limit)  level b  k  Acc _≺_ b
  outer k ih b q = accInside k ih here
    (Ordered.wellFounded k (stageOrder k) here) b q refl
    where
    here : Point k
    here = b .fst , subst  j   b .fst ∈ˢ finiteStage j ) q (level-in b)

limit-wf : WellFounded _≺_
limit-wf a = accByLevel (level a) a refl

limitOrder : SWO Limit
limitOrder = record
  { _<∙_   = _≺_
  ; tri∙   = limit-tri
  ; irr∙   = limit-irrefl
  ; trans∙ = limit-trans
  ; wf∙    = limit-wf }

Recap

Tally is all the finiteness this chapter owns: a finite family that hits every member, with no injectivity and no decidable equality asked for.

PowerStep.powerTally carries one up to the definable power set, by enumerating the bit vectors over the tally and observing that every subset of a tallied stage is definable; stageOrder then runs that step along the numerals, so every finite stage has a tally.

precedes compares two subsets at the earliest point where they disagree. It is irreflexive for free, transitive by comparing two witnesses, and trichotomous by the excluded middle together with the base's smallest elements. Well-foundedness is not a property of the comparison at all: it comes from the tally, through Search, and would fail over an infinite base, which is why the finiteness had to be established first.

limitOrder is a strict well-order on the members of Lset ω, with the level as the primary key and each finite stage's own order inside a level. It is the interface the axiom of choice will take: with it,

leastOf picks a member out of any inhabited property of members of the limit stage, and picks the same one every time.