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) ( : 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∈) ∣₁

最小元与良基性

现在轮到论证中使用点名册、而非制造点名册的那一半。固定一个类型及其上一个三歧、非自反且传递的关系,也就是严格良序所要求的一切,只差良基。

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,且 xyz 之下一致,意即 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∈ })

传递性与三歧确实需要关于基底序的前提,而二者所需不同,故一并收进一个模块:RA 的诸成员上的三歧与传递,以及 R 在那些成员上的最小元原则。在塔中,这些都来自下面那个阶段。

传递性是两个见证之间的比较。若 xp 处先于 yyq 处先于 z,则 pq 不可能相等,因为 p 属于 yq 不属于;而二者中较小的那个就见证了 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,且在无穷基底上会失效,这正是必须先立下有穷性的原因。

limitOrderLset ω 诸成员上的一个严格良序,以层号为主键,层内则用各有穷阶段自己的序。它就是选择公理将要取用的接口:有了它,leastOf 能从极限阶段诸成员的任一非空性质中挑出一个成员,且每次挑出同一个。