The finite stages, and the order they carry
上一章为一个族的每一格定位了该格首次拥有成员的那个阶段,并证明了它是一个后继。于是该格中恰在那里现身的每个成员,都是同一个集合的可定义子集:一个写在单一阶段之上的名字。尚缺的是比较这些名字的办法,而本章要在塔的底部造出的正是这种比较。
两个论断撑起本章。第一,凡以数码为索引的阶段都是有穷的,其确切含义见下文:它附带一份有穷的集合清单,命中它的全部成员。第二,有穷阶段带有一个良序,其比较方式是看两个成员最先在何处出现分歧,并把较大的位置判给二者中含有该处的那一个。
第二个论断是数学内容所在,而它在本质上是关于有穷集合的论断。若把同一套配方用到自然数的子集上,就会出现无穷下降:全体自然数,然后是从一开始的全体,再是从二开始的全体,如此下去,每一步删掉最先幸存的那一点,因而严格落到更低处。配方本身并不禁止这件事;在有穷基底上禁止它的,是有穷基底只有有穷多个子集,故寻找最小者的搜索会终止。下文良基性的证明走的正是这条路:一份有穷清单加上一个线序,就给出任何非空性质的最小成员,办法是扫过清单并留下最好的一次命中;而「每个非空性质都有最小成员」在经典意义下就是良基性。
有穷性之所以能沿塔上爬,是因为有穷集合的可定义子集就是它的全部子集,而带清单的集合只有有穷多个子集,每个清单上的位向量对应一个。于是一个阶段的清单给出下一个阶段的清单,递归再无所求。
极限阶段随即装配起来,不必再为「有穷诸序如何互相嵌套」多费功夫,因为它们并不嵌套:按最先分歧处比较的序,并不从一个阶段延拓到下一个阶段。取而代之的主键是楼层号。极限中首次现身于不同有穷阶段的两个成员,仅凭那两个阶段号比较;首次现身于同一阶段的两个成员,则按那个阶段自己的序比较。别的都不需要,也别的都不成立。
{-# 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 𝒮ᵥ
点名册
有穷性以点名册的身份入场:一个数、这么多个都属于 A 的集合所成的族,外加一句「A 的每个成员都仅仅是其中之一」。onto 读作「该族命中所有人」。
对重复不作要求,对判定相等也不作要求:点名册是从有穷索引出发的满射,不是双射。这是有意为之。前方的两处用法是一次扫描 (看见同一个元素两次也无妨) 与一个位向量 (同样无妨),而要求得越少,下一个阶段的点名册就越便宜。本章全部的有穷性词汇,就是这个 record 加上「由一份点名册造出另一份」的索引算术。
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) ∥₁
劈开一个有穷索引
为幂集清点,意味着枚举位向量,而长度为 n + 1 的向量数是长度为 n 的两倍。于是需要一小块索引算术:小于 a + b 的索引,要么是小于 a 的索引,要么是小于 b 的索引,反之亦然。两个来回中只有一个真正被用到,故只证那一个;bumpLeft 则是让沿 a 的递归通过类型检查的那次移位。
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))
枚举掩码
长度为 n 的掩码是一个 n 位的向量;对一个已清点的集合,它说明保留哪些条目。掩码共有 maskCount n 个,这个数是二的 n 次幂,写成反复加倍的形式,而 maskAt 把一个索引读成一个掩码:把索引对半劈开,它落在哪一半就由哪一半供给首位,其余部分供给尾巴。每个掩码都从某个索引读得,这就是 mask-onto,而这也是任何人对这个枚举唯一需要的性质。它并非逐点单射,也不必是。
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))
选出一个子族
select 把掩码作用到一个族上:它保留那些位为 true 的条目,并把它们重新交回为一个族,连同族自身的长度。长度是由递归产生的,这正是关键:无须计数,也没有任何算术把答案与掩码联系起来。
两条规格说明结果含有什么,且二者都不带截断,因为它们都是从同一次递归上直接读出的。marks 走的是反方向,把对诸条目的一次判定变成记录该判定的掩码。
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
把一个真值判定成一位
排中律交出的是一个析取,而掩码要的是一位,故须为二者引见。裁决作为实参收下,而不是在定义内部去查:正是这一点让两条来回引理能靠对它作模式匹配来证明;而真值本身显式给出,因为埋在 ⟨_⟩ 之下的隐式实参从来推不出来。
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)
已清点阶段的可定义子集
下面就是让有穷性上爬的那一步。固定一个序数 σ 与阶段 Lset σ 的一份点名册。点名册的每个条目都是该阶段的成员,故各自在该阶段的小成员类型中有一个名字,而这正是基本公理一章的有穷析取所要的;part 把掩码作用到这些名字上,取它们张成的有穷集合。该集合是这个阶段的可定义子集,理由已记在那里:「等于这一个」的有穷析取把它刻了出来。
两条规格把属于 part v 与掩码双向联系起来。然后是逆向:给定任一可定义子集 x,按点名册的每个条目是否属于 x 给它打上标记,则该掩码的 part 就是 x。一个方向由规格直接得到;另一个方向需要 x 不出该阶段,这样 x 的每个成员才首先会被点名册命中。于是诸掩码为可定义子集清了点,而一个阶段的点名册给出下一个阶段的点名册。
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∈) ∣₁
最小元与良基性
现在轮到论证中使用点名册、而非制造点名册的那一半。固定一个类型及其上一个三歧、非自反且传递的关系,也就是严格良序所要求的一切,只差良基。
scan 走过一个有穷族,返回的要么是一个满足该谓词、且在满足者之中最小的条目,要么是「没有条目满足它」的保证。它是沿长度的普通递归:每一步由排中律判定谓词在头部是否成立,由三歧比较头部与迄今为止的最佳者,四种组合即四条子句。全程无一处截断,而这很要紧,因为调用方要的是一个货真价实的元素,不是仅仅的存在性。
给定一个命中所有人的族,least 把它升级为「整个类型上任一非空谓词的最小元」:「没有条目满足它」那一支被见证者驳倒,因为该谓词本该命中它在族中的纤维。
良基性随之而来,而有穷性正是花在这里。可及是一个命题,故排中律判定它。若某个元素不可及,则存在一个最小的不可及者;于是比它小的一切皆可及,这反倒使它可及。矛盾即是证明。
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)
自然数,良序化
本章有一个序不是有穷的,正是数楼层的那一个。关于自然数上通常的序,库已备齐一切,故这个束是装配出来的、而非证出来的:三歧取库的判定程序,把它的三路答案改个名;良基性则直接是库自己的。
提升只是记账,别无他意。一个束把它的关系带在为全章一次固定的单一宇宙层级上,而自然数上的序住在最底层,故把它抬上来相会。这也是良序那一章头一回被真正使唤。
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)
最先的分歧
固定一个集合 A 与集合之上的一个关系 R,后者读作 A 的诸成员上的一个序。A 的两个子集,按它们在何处分歧来比较。「x 先于 y」的见证,是 A 的一个成员 z,它属于 y 而不属于 x,且 x 与 y 在 z 之下一致,意即 A 中被 R 排在 z 之前的每个成员,属于其中之一当且仅当属于另一个。倒过来读:z 就是最先的分歧点,而 y 是持有它的那一个。
非自反性立刻成立,且完全不需要任何前提:x 对自己的见证会既属于 x 又不属于 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∈ })
传递性与三歧确实需要关于基底序的前提,而二者所需不同,故一并收进一个模块:R 在 A 的诸成员上的三歧与传递,以及 R 在那些成员上的最小元原则。在塔中,这些都来自下面那个阶段。
传递性是两个见证之间的比较。若 x 在 p 处先于 y,y 在 q 处先于 z,则 p 与 q 不可能相等,因为 p 属于 y 而 q 不属于;而二者中较小的那个就见证了 x 先于 z。两支要核对的是同样两件事:较小的那一点站对了边,以及它之下的一致性可以复合。
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))
三歧正是花掉排中律与最小元原则的地方。先问这两个子集在 A 中是否有分歧之处。若没有,则它们在 A 中处处一致;又因二者都不出 A,故它们根本就处处一致,外延性把它们认同。若有,则存在一个最先的分歧点,再作一次判定,即该点是否属于第一个子集,就说明比较朝哪个方向走。该点之下的一致性在两支中都是白得的:按该点的选法,它之下无一处分歧。
排中律在 agree 内部第二次被使用,用来把「没有分歧」变成「一致」;这一步恰是一次双重否定的消去,再便宜不了。
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)
有穷诸阶段
以数码为索引的阶段就是有穷的那些,而每个阶段上的序沿递归造出:零阶段是空的,而 n 之后那个阶段上的序,是在阶段 n 之上按最先分歧处的比较,以阶段 n 自己的序为基底。before-irrefl 在每个阶段都成立且无须归纳,因为该比较的非自反性本就不要前提,而零阶段根本不带任何比较。
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 δ∈)
递归必须携带的是一份点名册、三歧与传递,别无其他:非自反性在每个阶段都是白得的,而良基性在用到之处现推、不搬运。阶段的一个点,是一个集合连同它的隶属证明,而隶属是命题,故两个点只要集合相等就相等;这就是在「关于集合的陈述」与「载体必须是类型的那个束」之间往返时,全部的记账工作。
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)
然后是递归本身。零处,一切都由该阶段为空而清账。后继处,点名册是上一个阶段的点名册经可定义幂集抬上来的,而两条序的事实就是关于最先分歧处的那两条定理,施用时由上一个阶段供给它的三歧、它的传递与它的最小元。「后继阶段与其下的可定义幂集相认同」这一点用了三次,每个字段一次,且每次都只用来把一句隶属陈述搬过去。
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
极限阶段
极限阶段的成员现身于某个有穷阶段,因为极限是其下诸阶段的并,而它们各自都以数码为索引。在它已现身的那些数码之中有一个最小者,那个数就是它的层号。这是本章唯一花掉自然数良序的地方,而花掉它的正是良序那一章的极小元定理。
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
极限上的序以层号为主键:层号较低的成员排在前面,而同层的两个成员按该层自己的序比较。层号之间的等式携带在第二支中,且携带的方向使得第二个成员可以在第一个成员的层上读出,正是这一点让定义中不出现任何搬运。
非自反与传递是对那一支的分情形,其中层号等式把阶段序的事实搬到需要它的那一层上。三歧先比较层号,只有层号相同时才交给阶段处理。
_≺_ : 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))
良基性是两层嵌套的归纳,而把它们分开是有意的。外层是对层号的归纳,取库封装好的形式,它交下一个覆盖所有更低层的假设。内层是沿有穷阶段本已具备的可及性作普通下降,而这之所以合法,恰恰是因为那个阶段有穷。降一层的一步诉诸外层假设;层内的一步诉诸内层假设;而由于内层函数除自己的可及性实参外不沿任何东西递归,二者从不需要放在一起比较。
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 }
小结
Tally 就是本章拥有的全部有穷性:一个命中每个成员的有穷族,既不要求单射,也不要求可判定的相等。PowerStep.powerTally 把它抬到可定义幂集上,办法是枚举点名册上的位向量,并指出已清点阶段的每个子集都可定义;stageOrder 随后沿诸数码跑完这一步,于是每个有穷阶段都有一份点名册。
precedes 在两个子集最先分歧之处比较它们。它的非自反性是白得的,传递性由比较两个见证得到,三歧则由排中律连同基底的最小元得到。良基性压根不是这个比较自身的性质:它来自点名册,经由 Search,且在无穷基底上会失效,这正是必须先立下有穷性的原因。
limitOrder 是 Lset ω 诸成员上的一个严格良序,以层号为主键,层内则用各有穷阶段自己的序。它就是选择公理将要取用的接口:有了它,leastOf 能从极限阶段诸成员的任一非空性质中挑出一个成员,且每次挑出同一个。