Codes in the hierarchy

上一章把语法编码进任何提供两样东西的结构:一个单射的配对,以及自然数的一个单射。层级两样都提供,而本章把它们兑现出来。二者都不是新数学;二者都是这门学科里最老的把戏,之所以要占一章,只因为单射性必须被证明

自然数这边,层级自己的数码即可胜任。相异的数码是相异的集合,因为较小的数码属于较大的,而没有集合属于自身。配对这边,Kuratowski 的编码即可胜任:ab 的对,是以 a 的单点集与 ab 的无序对为成员的那个集合,于是第一分量可作为公共元素还原,第二分量则作为那个可能不同的元素还原。

两个证明全程只经库的分类规格进行,沿路径搬运隶属关系。任何时候都不把嵌套的花括号表达式交给类型检查器去展开,这是纪律而非美学:这些编码嵌套三层深,而展开其中之一,正是关于它们的证明停止终止的方式。

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

open import Base.Prelude
open import Base.Truth

module V.Coding { : Level} where

open import FOL.ZFStructure using ( module hPropStructure )
import FOL.Coding
open import V.Hierarchy {} using ( 𝒮ᵥ; ∈-irrefl )
open import V.Model {} using ( self∈sucV; ∈sucV-inl )

open import Cubical.Data.Nat.Order using ( _<_; <-split; ¬-<-zero; _≟_; lt; eq; gt )
import Cubical.Data.Empty as Empty
import Cubical.Data.Sum as Sum
open Sum using ( _⊎_; inl; inr )
import Cubical.HITs.PropositionalTruncation as PT
open PT using ( ∣_∣₁; ∥_∥₁ )
open import Cubical.HITs.CumulativeHierarchy.Base using ( setIsSet )
open import Cubical.HITs.CumulativeHierarchy.Properties using ( _∈ₛ_ )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( ⁅_,_⁆; pairing-ax; ⁅_⁆s; SingletonPackage; module InfinitySet )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( SetPackage )  -- lint-agda: keep (used qualified: SetPackage.classification)
open InfinitySet using ( #_ )

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

数码两两相异

先看单调性:较小的数码属于较大的。归纳沿较大的那个序号进行,使得每一步都是句法上的后继,索引上不出现任何算术。这是有意为之。若改沿差量归纳,就会把 suc k + msuc (k + m) 对上,而化简那个等式会迫使隶属类型经后继、并与小成员类型展开,那是走不完的。

分情形用显式消去子而非 with 写出,理由相同:with 会抽象目标,而抽象这个目标就会把它归一化。

#⊆suc : (n : ) {x : S}   x ∈ˢ (# n)    x ∈ˢ (# (suc n)) 
#⊆suc n {x} = ∈sucV-inl {A = # n} {x = x}

#mono : (m n : )  m < n   (# m) ∈ˢ (# n) 
#mono m zero    m<0    = Empty.rec (¬-<-zero m<0)
#mono m (suc n) m<sucn = Sum.rec
   m<n  #⊆suc n (#mono m n m<n))
   m≡n  subst  M   (# M) ∈ˢ (# (suc n)) ) (sym m≡n) (self∈sucV (# n)))
  (<-split m<sucn)

单射性随即由序号上的三歧得出。序号相等即是结论;若严格更小,则把两个码认同之后会把某个数码放进它自身,而无自环性禁止这一点;余下的情形是镜像。

#-inj : (m n : )  # m  # n  m  n
#-inj m n #m≡#n with m  n
... | eq m≡n = m≡n
... | lt m<n = Empty.rec (∈-irrefl (# n)
      (subst  z   z ∈ˢ (# n) ) #m≡#n (#mono m n m<n)))
... | gt n<m = Empty.rec (∈-irrefl (# m)
      (subst  z   z ∈ˢ (# m) ) (sym #m≡#n) (#mono n m n<m)))

#-inj′ :  {m n}  # m  # n  m  n
#-inj′ {m} {n} = #-inj m n

Kuratowski 配对

先把分类规格各命名一次,好让证明读起来像隶属关系的推理,而不是花括号的摆弄。属于单点集就是等于它那个元素;属于无序对就是仅仅等于二者之一。由此,单点集决定它的元素;而恰好等于某个无序对的单点集,会把两个分量都压到那个元素上。

private
  ∈singl : {a x : S}   x ∈ₛ  a ⁆s   x  a
  ∈singl {a} {x} = SetPackage.classification (SingletonPackage a) x .fst

  singl∈ : {a x : S}  x  a   x ∈ₛ  a ⁆s 
  singl∈ {a} {x} = SetPackage.classification (SingletonPackage a) x .snd

  self∈singl : (a : S)   a ∈ₛ  a ⁆s 
  self∈singl a = singl∈ refl

  inl∈⁅,⁆ : {a b x : S}  x  a   x ∈ₛ  a , b  
  inl∈⁅,⁆ {a} {b} {x} e = pairing-ax a b x .snd  inl e ∣₁

  inr∈⁅,⁆ : {a b x : S}  x  b   x ∈ₛ  a , b  
  inr∈⁅,⁆ {a} {b} {x} e = pairing-ax a b x .snd  inr e ∣₁

  mem⁅,⁆ : {a b x : S}   x ∈ₛ  a , b     (x  a)  (x  b) ∥₁
  mem⁅,⁆ {a} {b} {x} = pairing-ax a b x .fst

  singl-inj : {a c : S}   a ⁆s   c ⁆s  a  c
  singl-inj {a} {c} q = ∈singl (subst  s   a ∈ₛ s ) q (self∈singl a))

  singl≡pair : {a c d : S}   a ⁆s   c , d   (c  a) × (d  a)
  singl≡pair {a} {c} {d} q =
      ∈singl (subst  s   c ∈ₛ s ) (sym q) (inl∈⁅,⁆ {a = c} {b = d} refl))
    , ∈singl (subst  s   d ∈ₛ s ) (sym q) (inr∈⁅,⁆ {a = c} {b = d} refl))

配对本身,以及本章为之存在的那条定理。两个分量都是把一个隶属关系沿假设的等式搬运过去、再对结果作分类而还原的。第一个分量较易;第二个需要处理退化情形,即两个分量重合使对塌陷的情形,那里缺失的信息靠向另一个方向搬运补回。

pr : S  S  S
pr a b =   a ⁆s ,  a , b  

pr-inj :  {a b c d}  pr a b  pr c d  (a  c) × (b  d)
pr-inj {a} {b} {c} {d} p = a≡c , b≡d
  where
  H₁ :  ( a ⁆s   c ⁆s)  ( a ⁆s   c , d ) ∥₁
  H₁ = mem⁅,⁆ (subst  s    a ⁆s ∈ₛ s ) p (inl∈⁅,⁆ {b =  a , b } refl))

  a≡c : a  c
  a≡c = PT.rec (setIsSet a c)
    (Sum.rec singl-inj  e  sym (singl≡pair e .fst))) H₁

  H₂ :  ( a , b    c ⁆s)  ( a , b    c , d ) ∥₁
  H₂ = mem⁅,⁆ (subst  s    a , b  ∈ₛ s ) p (inr∈⁅,⁆ {a =  a ⁆s} refl))

  K :  ( c , d    a ⁆s)  ( c , d    a , b ) ∥₁
  K = mem⁅,⁆ (subst  s    c , d  ∈ₛ s ) (sym p) (inr∈⁅,⁆ {a =  c ⁆s} refl))

  d≡b-from-K : a  b  d  b
  d≡b-from-K a≡b = PT.rec (setIsSet d b)
    (Sum.rec
       e  singl≡pair (sym e) .snd  a≡b)
       e  PT.rec (setIsSet d b)
        (Sum.rec  d≡a  d≡a  a≡b)  d≡b  d≡b))
        (mem⁅,⁆ (subst  s   d ∈ₛ s ) e (inr∈⁅,⁆ {a = c} refl)))))
    K

  b≡d : b  d
  b≡d = PT.rec (setIsSet b d)
    (Sum.rec
       e  let b≡c = singl≡pair (sym e) .snd
             in sym (d≡b-from-K (a≡c  sym b≡c)))
       e  PT.rec (setIsSet b d)
        (Sum.rec
           b≡c  sym (d≡b-from-K (a≡c  sym b≡c)))
           b≡d  b≡d))
        (mem⁅,⁆ (subst  s   b ∈ₛ s ) e (inr∈⁅,⁆ {a = a} refl)))))
    H₂

实例

两组参数都已兑现,编码那一章便适用于层级,而以层级自家集合为常元的公式,获得的码又是层级的集合。这就是第四部的诸证书所读写的对象。

module VCode = FOL.Coding {ℓ-suc } 𝒮ᵥ pr pr-inj #_ #-inj′

小结

数码单射 (#-inj,经单调性与无自环性),Kuratowski 对单射 (pr-inj,经分类规格),于是 VCode 就是上一章的编码施于层级。公式如今是 V 的集合,Codes 关系可用来对它们推理,而第四部可以开始搭建对编码语法作量化的证书了。