可以直接阅读本章,也可以通过交互式目录和依赖图选择其他路线。
交互式目录 · 依赖图固定宇宙层级 ℓ,并假设 lem : LEM (ℓ-suc ℓ)。这个假设为相应层级的每个命题提供判定,并始终作为下文构造的显式参数。
module L.Coding.CodeSet {ℓ : Level} (lem : LEM (ℓ-suc ℓ)) where
本章利用封闭码定义域分离出一个可构造集合,其中恰好包含所有元数上携带所需形状与封闭见证的公式码。其成员关系定理给出码、元数数码与解码公式三者之间的相互转换。
open import Cubical.HITs.CumulativeHierarchy.Base using ( V; _∈_ )
open import Cubical.HITs.CumulativeHierarchy.Properties
using ( ⟪_⟫; ⟪_⟫↪; ∈∈ₛ; ∈ₛ⟪_⟫↪_; ∈-asFiber )
open import Cubical.HITs.CumulativeHierarchy.Constructions
using ( module InfinitySet )
open InfinitySet using ( #_ )
open hPropView 𝒮ʟ
module ModelL = FOL.ZFModel 𝒮ʟ
open ModelL using ( SetOf )
module AbsL = FOL.Absoluteness.Single 𝒮ᵥ isL isL-trans
open AbsL renaming ( _⊨ᵐ_ to _⊨_ )
是某个已言明元数处的键
本节给出一条读式,也是本章唯一新增的对象语言陈述。元数 k 处的键是第一分量为数码 k 的对;已有的标签读式描述第二分量已被点名的情形。这里不指定第二分量,因此把标签读式置于一个存在量词之下。两个方向分别来自该存在量词的引入与消去,并在内部使用标签读式的充分性等式。
该等式在索引、数码与环境仍为变元时证明;保持这些参数为变元,才能避免后续实例化产生额外的转换检查开销。
keyArityAtL : ∀ {n} → Fin n → ℕ → Formula S n
keyArityAtL c k = ∃̇ (tagAtL (suc c) k zero)
keyArityAtL-out : ∀ {n} (c : Fin n) (k : ℕ) (γ : Vec S n)
→ ⟨ γ ⊨ keyArityAtL c k ⟩
→ ∥ (Σ[ z ∶ S ] ((lookup c γ) .fst ≡ pr (# k) (z .fst))) ∥₁
keyArityAtL-out c k γ = map₁
(λ { (z , hz) →
z , subst ⟨_⟩ (tagAtL-adequate (suc c) k zero (z ∷ γ)) hz })
keyArityAtL-in : ∀ {n} (c : Fin n) (k : ℕ) (γ : Vec S n) (z : S)
→ (lookup c γ) .fst ≡ pr (# k) (z .fst)
→ ⟨ γ ⊨ keyArityAtL c k ⟩
keyArityAtL-in c k γ z e =
∣ z , subst ⟨_⟩ (sym (tagAtL-adequate (suc c) k zero (z ∷ γ))) e ∣₁
是某个元数处的键
上一条读式把元数指定为一个元语言的数码,而正是这一点把元数固定为一;一个必须容纳诸子码的集合无法做到这一点,因为量词的子公式位于高一级的元数上。因此元数必须变成一个被绑定的集合,而还须有某个东西向那个集合说明 # k 直接给出的事实:它是一个数码。
表达它只需一个常元。ωʟ 是 L 的元素,其元素恰是诸数码,故「元数分量属于 ωʟ」就是那个条件,而且写法与第二个合取项已经在用的那种无界成员关系相同。全式共有两个存在量词,分别约束元数与载荷,中间是对读式,再加上落在元数上的那条成员关系。
从反方向读时,这一选择的作用才显现出来。ω-specL 是命题之间的等式而非蕴含,故 ωʟ 的元素就是一个被截断的自然数;与链的投影等式复合一次,就把它变成 recover 作为元数实参所接受的那个 # m。两个方向都不需要归纳;数码那一章已经完成了。
arityNumAtL : ∀ {n} → Fin n → Formula S n
arityNumAtL c = ∃̇ (∃̇ (prAtL (suc (suc c)) (suc zero) zero
∧̇ (var (suc zero) ∈̇ con ωʟ)))
arityNumAtL-out : ∀ {n} (c : Fin n) (γ : Vec S n)
→ ⟨ γ ⊨ arityNumAtL c ⟩
→ ∥ (Σ[ m ∶ ℕ ] Σ[ z ∶ S ]
((lookup c γ) .fst ≡ pr (# m) (z .fst))) ∥₁
arityNumAtL-out c γ = rec₁ squash₁ (λ { (ar , h) →
rec₁ squash₁ (λ { (z , (hp , hω)) → map₁
(λ { (m , qm) → lower m , z
, ( subst ⟨_⟩
(prAtL-adequate (suc (suc c)) (suc zero) zero (z ∷ ar ∷ γ)) hp
∙ cong (λ w → pr w (z .fst)) (qm ∙ numeralL-fst (lower m)) ) })
(subst ⟨_⟩ (ω-specL ar) hω) }) h })
arityNumAtL-in : ∀ {n} (c : Fin n) (γ : Vec S n) (m : ℕ) (z : S)
→ (lookup c γ) .fst ≡ pr (# m) (z .fst)
→ ⟨ γ ⊨ arityNumAtL c ⟩
arityNumAtL-in c γ m z e = ∣ numeralL m , ∣ z
, ( subst ⟨_⟩ (sym (prAtL-adequate (suc (suc c)) (suc zero) zero
(z ∷ numeralL m ∷ γ)))
(e ∙ cong (λ w → pr w (z .fst)) (sym (numeralL-fst m)))
, subst ⟨_⟩ (sym (ω-specL (numeralL m))) ∣ lift m , refl ∣₁ ) ∣₁ ∣₁
谓词
两个合取项都落在同一个自由变元上。第一项从外部固定元数,而这正是上一章明确要求的那一项。第二项是解码那两条假设的见证:一个装着实参、既封闭又成形的集合。
第二项里没有任何东西是有界的,也不需要有。引入一方由一条公式自己的子公式闭包给出该见证,消去一方则把它作为 L 的一个集合来使用,两种读法都发生在类模型处。
第二个合取项有两种写法:一般形式使用载体与实参两个槽位;常元形式则把载体固定为常元。一般形式只用一个存在量词绑定相应集合;常元形式在外层再加入一个以 A 命名的绑定。这个额外绑定是两种写法的全部差别。
hasWitnessAt : ∀ {n} → Fin n → Fin n → Formula S n
hasWitnessAt A x = ∃̇ ((var (suc x) ∈̇ var zero)
∧̇ (closedAt zero ∧̇ shapedAt zero (suc A)))
hasWitness : S → Formula S 1
hasWitness A = ∃̇ ((var zero ≐ con A) ∧̇ hasWitnessAt zero (suc zero))
isCodeAny : S → Formula S 1
isCodeAny A = arityNumAtL zero ∧̇ hasWitness A
超集与集合
载体固定后,使用方会把它取为某一层。载体的元素构成字母表,正好提供编码章要求的两项参数:到层级的嵌入,以及该嵌入每个取值可构造的证明。后一项由 L 的传递性得到。相应的成员关系单独命名,因为形状谓词直接以该关系为参数。
接着构造所需超集。smallDom 接收 L 元素的小族,并返回包含该族所有元素的层。这里的小族以「一个元数及该元数处的一条公式」组成的对为索引。其尺寸满足要求,因为语法是字母表所在层级上的归纳类型,而自然数索引不会提高该尺寸。所得层含有每个键,也含有其他元素;最后用分离去除这些额外元素。
这个集合在构造处被封印。若不封印,此后每个提到它的类型都会把分离定义的展开带入转换检查,而这里导出的事实已经足够所有使用方使用。封印内部只保留读取分离结果所需的引理;由这些方向复合得到的等式放在封印外部,因为它们不依赖该集合从哪个超集中分离出来。
module _ (A : S) where
private
ι : ⟪ A .fst ⟫ → V ℓ
ι = ⟪ A .fst ⟫↪
ι∈ : (m : ⟪ A .fst ⟫) → ⟨ ι m ∈ A .fst ⟩
ι∈ m = ∈∈ₛ {a = ι m} {b = A .fst} .snd (∈ₛ⟪ A .fst ⟫↪ m)
ιL : (m : ⟪ A .fst ⟫) → ⟨ isL (ι m) ⟩
ιL m = isL-trans {x = A .fst} {y = ι m} (ι∈ m) (A .snd)
codeS : ∀ {n} → Formula ⟪ A .fst ⟫ n → S
codeS φ = VCode.⌜ mapFo ι φ ⌝ , codeL ι ιL φ
keyS : ∀ {n} → Formula ⟪ A .fst ⟫ n → S
keyS φ = key ι ιL φ , keyL ι ιL φ
private
smallAny : Σ[ d ∶ S ] ((p : Σ[ n ∶ ℕ ] Formula ⟪ A .fst ⟫ n)
→ ⟨ keyS (p .snd) ∈ˢ d ⟩)
smallAny = smallDom (Σ[ n ∶ ℕ ] Formula ⟪ A .fst ⟫ n) (λ p → keyS (p .snd))
sepAny : isContr
(SetOf (λ x → (x ∈ˢ smallAny .fst) ⊓ ((x ∷ []) ⊨ isCodeAny A)))
sepAny = hasSeparationL (smallAny .fst) (isCodeAny A)
见证的引入与消去
第二个合取项的两半都在此处证明,且是在变元元数、变元载体位与变元环境上一次证成,下面的一切只是把它们再应用一遍。元数可以是变元,因为那个合取项根本不提及它:引入为任意元数的一条公式产出一个既封闭又成形的集合,消去则接受这样的集合并调用解码,而解码从一开始就把元数作为实参。载体与环境可以是变元,则是因为两半所依赖的每条引理本来就是这样陈述的。
引入是其中不涉及额外内容的那一半。那个见证是子公式闭包,它的三个组成部分 key∈closure、closureClosed 与 closureShaped 各有一章专门处理,且都已完成。其中最后一条还多需要一件东西,即每个常元都是载体的元素;在这个字母表上,这正是当初据以定义字母表的那件事,沿那一位的等式搬过去即可。
消去是另一半。它从一个元素出发,这个元素以某个已言明元数处的键的形式给出,这正是 recover 所要求的,也是第二个合取项无法直接提供的。载体那一位的等式把「属于那一位所持有的东西」变成「属于 A」,解码那条假设因此得以应用:A 的诸元素恰是 ⟪ A ⟫ 的像,依据是「一个集合由其自身诸元素所呈现」。读出那个存在量词,就得到一个既封闭又成形的集合。随后运行解码,其答案是载体之上、落在所给定的那个元数处的一条公式。
这两个方向都应用于由外层具名绑定构造的环境,其中载体由等式固定。引入方向为该绑定提供 A,并用 refl 证明等式;消去方向读出该绑定,再把其中的数据传给一般形式。读取绑定之处必须显式写出载荷类型。 若让类型检查器推断,载体处的截断载荷会成为一个元变元,表示尚未确定公式的满足关系。同样两行代码,显式写出类型时两秒完成,不写时超过 140 秒后终止。该现象来自具体环境处的 rec₁,与图本身无关。
witnessAt-in : ∀ {n k} (b c : Fin n) (γ : Vec S n) (φ : Formula ⟪ A .fst ⟫ k)
→ (lookup b γ) .fst ≡ A .fst
→ (lookup c γ) .fst ≡ (keyS φ) .fst
→ ⟨ γ ⊨ hasWitnessAt b c ⟩
witnessAt-in b c γ φ qb qc = ∣ clo ι ιL φ
, ( subst (λ w → ⟨ w ∈ (clo ι ιL φ) .fst ⟩) (sym qc) (key∈closure ι ιL φ)
, ( closureClosed ι ιL φ γ
, closureShaped ι ιL φ b γ
(λ m → subst (λ w → ⟨ ι m ∈ w ⟩) (sym qb) (ι∈ m)) ) ) ∣₁
witnessAt-out : ∀ {n} (b c : Fin n) (γ : Vec S n)
→ (lookup b γ) .fst ≡ A .fst
→ ⟨ γ ⊨ hasWitnessAt b c ⟩
→ (k : ℕ) (z : S) → (lookup c γ) .fst ≡ pr (# k) (z .fst)
→ ∥ (Σ[ ψ ∶ Formula ⟪ A .fst ⟫ k ]
((lookup c γ) .fst ≡ (keyS ψ) .fst)) ∥₁
witnessAt-out b c γ qb hw k z qz = rec₁ squash₁ viaSlot hw
where
Target : Type (ℓ-suc ℓ)
Target = ∥ (Σ[ ψ ∶ Formula ⟪ A .fst ⟫ k ]
((lookup c γ) .fst ≡ (keyS ψ) .fst)) ∥₁
onto : (y : V ℓ) → ⟨ y ∈ (lookup b γ) .fst ⟩
→ ∥ Σ[ m ∶ ⟪ A .fst ⟫ ] (ι m ≡ y) ∥₁
onto y y∈ = ∣ ∈-asFiber {a = y} {b = A .fst}
(subst (λ w → ⟨ y ∈ w ⟩) qb y∈) ∣₁
viaSlot : Σ[ C ∶ S ] ⟨ (C ∷ γ) ⊨ ((var (suc c) ∈̇ var zero)
∧̇ (closedAt zero ∧̇ shapedAt zero (suc b))) ⟩
→ Target
viaSlot (C , (x∈C , (hcl , hsh))) = map₁
(λ { (ψ , qψ) → ψ , (qz ∙ cong (pr (# k)) (sym qψ)) })
(Decode.recover ι zero (suc b) (C ∷ γ) onto hcl hsh k z
(subst (λ w → ⟨ w ∈ C .fst ⟩) (qz ∙ sym (keyOf-fst k z)) x∈C))
private
witness-in : ∀ {n} (φ : Formula ⟪ A .fst ⟫ n)
→ ⟨ (keyS φ ∷ []) ⊨ hasWitness A ⟩
witness-in φ = ∣ A , ( refl
, witnessAt-in zero (suc zero) (A ∷ keyS φ ∷ []) φ refl refl ) ∣₁
witness-out : (x : S) → ⟨ (x ∷ []) ⊨ hasWitness A ⟩
→ (k : ℕ) (z : S) → x .fst ≡ pr (# k) (z .fst)
→ ∥ (Σ[ ψ ∶ Formula ⟪ A .fst ⟫ k ] (x .fst ≡ (keyS ψ) .fst)) ∥₁
witness-out x hw k z qz = rec₁ squash₁ viaCarrier hw
where
viaCarrier : Σ[ B ∶ S ] ⟨ (B ∷ x ∷ [])
⊨ ((var zero ≐ con A) ∧̇ hasWitnessAt zero (suc zero)) ⟩
→ ∥ (Σ[ ψ ∶ Formula ⟪ A .fst ⟫ k ] (x .fst ≡ (keyS ψ) .fst)) ∥₁
viaCarrier (B , (qB , hB)) =
witnessAt-out zero (suc zero) (B ∷ x ∷ []) qB hB k z qz
每个元数上的集合
得到的是载体之上诸公式在任意元数处的诸键之类,而「对诸子码作递归」必须以这一类为索引,因为量词的子公式位于高一级的元数上,一元那一类容纳不下它。
IsKeyOverAny : S → hProp (ℓ-suc ℓ)
IsKeyOverAny x =
∥ (Σ[ n ∶ ℕ ] Σ[ ψ ∶ Formula ⟪ A .fst ⟫ n ] (x .fst ≡ (keyS ψ) .fst)) ∥₁
, squash₁
opaque
AllCodes : S
AllCodes = sepAny .fst .fst
key∈AllCodes : ∀ {n} (φ : Formula ⟪ A .fst ⟫ n) → ⟨ keyS φ ∈ˢ AllCodes ⟩
key∈AllCodes {n} φ = subst ⟨_⟩ (sym (sepAny .fst .snd (keyS φ)))
( smallAny .snd (n , φ)
, ( arityNumAtL-in zero (keyS φ ∷ []) n (codeS φ) refl
, witness-in φ ) )
AllCodes-out : (x : S) → ⟨ x ∈ˢ AllCodes ⟩ → ⟨ IsKeyOverAny x ⟩
AllCodes-out x x∈ = rec₁ squash₁
(λ { (k , z , qz) → map₁ (λ { (ψ , q) → k , ψ , q })
(witness-out x (sat .snd) k z qz) })
(arityNumAtL-out zero (x ∷ []) (sat .fst))
where
sat : ⟨ (x ∷ []) ⊨ isCodeAny A ⟩
sat = subst ⟨_⟩ (sepAny .fst .snd x) x∈ .snd
AllCodes-in : (x : S) → ⟨ IsKeyOverAny x ⟩ → ⟨ x ∈ˢ AllCodes ⟩
AllCodes-in x = rec₁ ((x ∈ˢ AllCodes) .snd)
(λ { (n , ψ , q) →
subst (λ w → ⟨ w ∈ AllCodes .fst ⟩) (sym q) (key∈AllCodes ψ) })
小结
一个集合,一条谓词。AllCodes 是 L 的元素,凭 AllCodes-out 与 AllCodes-in,它的诸元素恰是载体之上诸公式在每个元数处的诸键。
全部内容都在两个合取项里,而两者同类。封闭性与成形性合起来刻画的是码的形状,对一个键所携带的元数以及它的诸常元出自哪个字母表则完全未提,故一条针对它们写下的解码必须被给予这两样,而一个由它们造出的集合必须说明这两样。smallDom 与任意公式的分离处理其余,而两者所依赖的都只是前几章已经建立的结果。
这个集合的存在,是为了它所刻画的那一类,而不是为了某条关于它的定理。对码的递归必须在一个码的诸子码处给出答案,而量词的子公式位于高一级的元数上,一元那一类容纳不下它,故定义域只能是每个元数处的诸键。
{-# OPTIONS --cubical --safe --guardedness #-}open import Base.Preludeopen import Base.Classical using ( LEM )open import FOL.ZFStructure using ( module hPropView )open import FOL.Syntax using ( Formula; var; con; _∈̇_; _≐_; _∧̇_; ∃̇_ )open import FOL.Manipulation.ConstantMapping using ( mapFo )import FOL.Absolutenessimport FOL.ZFModelopen import V.Hierarchy {ℓ} using ( 𝒮ᵥ )open import V.Coding {ℓ} using ( pr; module VCode )open import L.Constructible {ℓ} using ( 𝒮ʟ; isL; isL-trans )open import L.Recursion {ℓ} lem using ( smallDom )open import L.Axioms.Full {ℓ} lem using ( hasSeparationL )open import L.Axioms.Numerals {ℓ} using ( numeralL; numeralL-fst )open import L.Axioms.Infinity {ℓ} lem using ( ωʟ; ω-specL )open import L.Coding.Model {ℓ} using ( prAtL; prAtL-adequate )open import L.Coding.Expressions {ℓ} using ( tagAtL; tagAtL-adequate )open import L.Coding.Closure {ℓ} using ( closedAt )open import L.Coding.CodeConstructibility {ℓ} using ( key; keyL; codeL; key∈closure )open import L.Coding.SubformulaClosure {ℓ} using ( clo; closureClosed )open import L.Coding.CodeShape {ℓ} using ( shapedAt; closureShaped )open import L.Coding.FormulaRecovery {ℓ} using ( keyOf-fst; module Decode )