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) (oσ : IsOrd σ) (t : Tally (Lset σ)) where open Tally t open FinOf σ oσ 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.