The table, and what it records
The recursion's answer, assembled. For a formula of the meta-language, the finite set of pairs of a key with the value at it, one pair for the formula and one for each subformula, built exactly as the subformula closure was and for the same reason: the meta level can name what it has already built.
Everything here is an element of the model by construction. The key is a pair of a numeral with a code, and the code is taken in the model's own coding, so no constructibility certificate is carried and none has to be proved. That is what the coding chapter's second instantiation bought, and this is the chapter that spends it.
What the recursion actually needs from the table is the other direction: any value recorded against a key is the value at that key. That is where the code equation has to be injective, and where a table that merely happened to record two things at one key would not be a function at all.
{-# OPTIONS --cubical --safe --guardedness #-} open import Base.Prelude open import Base.Truth open import Base.Classical using ( LEM ) module L.Coding.Table {ℓ : Level} (lem : LEM (ℓ-suc ℓ)) where open import FOL.ZFStructure using ( module hPropStructure ) open import FOL.Syntax using ( Formula; _∈̇_; _≐_; _∧̇_; _∨̇_; _⇒̇_; ¬̇_; ⊤̇; ⊥̇; ∃̇_; ∀̇_; ∀̇∈; ∃̇∈ ) open import V.Coding {ℓ} using ( pr; pr-inj; #-inj′ ) open import L.Constructible {ℓ} using ( 𝒮ʟ; isL ) open import L.Axioms.Numerals {ℓ} using ( numeralL; numeralL-fst ) open import L.Coding.Model {ℓ} using ( module LCode; prʟ; prʟ-fst ) open import L.Coding.InL {ℓ} using ( sglʟ; cupʟ; sglʟ-in; sglʟ-out; cupʟ-inl; cupʟ-inr; cupʟ-out ) open import L.Coding.Sat {ℓ} lem using ( Sat ) open import Cubical.Data.Sigma using ( Σ≡Prop ) open import Cubical.Data.Sum using ( inl; inr ) open import Cubical.Foundations.Prelude using ( J ) import Cubical.HITs.PropositionalTruncation as PT open PT using ( ∣_∣₁; ∥_∥₁; squash₁ ) open import Cubical.HITs.CumulativeHierarchy.Base using ( V; _∈_; setIsSet ) open import Cubical.HITs.CumulativeHierarchy.Constructions using ( module InfinitySet ) open InfinitySet using ( #_ ) open TruthAlgebra (hPropAlgebra (ℓ-suc ℓ)) open hPropStructure 𝒮ʟ using ( S )
Keys and entries
A key is the arity paired with the code, which is the shape every clause of the internal recursion reads. An entry is a key paired with the value.
The shape both live in is the same, so it is written once. tree gathers one thing per subformula, and what that thing is is its parameter: with the entry it gives the table, with the key it gives the slot the table is indexed by. The recursion needs both and needs them to agree constructor for constructor, which is a reason to build them from one recursion rather than two.
keyʟ : ∀ {n} → Formula S n → S keyʟ {n} φ = prʟ (numeralL n) LCode.⌜ φ ⌝ module _ (B : S) where ent : ∀ {n} → Formula S n → S ent φ = prʟ (keyʟ φ) (Sat B φ) tree : (∀ {m} → Formula S m → S) → ∀ {n} → Formula S n → S tree f φ@(t ∈̇ u) = sglʟ (f φ) tree f φ@(t ≐ u) = sglʟ (f φ) tree f φ@⊤̇ = sglʟ (f φ) tree f φ@⊥̇ = sglʟ (f φ) tree f φ@(a ∧̇ b) = cupʟ (sglʟ (f φ)) (cupʟ (tree f a) (tree f b)) tree f φ@(a ∨̇ b) = cupʟ (sglʟ (f φ)) (cupʟ (tree f a) (tree f b)) tree f φ@(a ⇒̇ b) = cupʟ (sglʟ (f φ)) (cupʟ (tree f a) (tree f b)) tree f φ@(¬̇ a) = cupʟ (sglʟ (f φ)) (tree f a) tree f φ@(∃̇ a) = cupʟ (sglʟ (f φ)) (tree f a) tree f φ@(∀̇ a) = cupʟ (sglʟ (f φ)) (tree f a) tree f φ@(∀̇∈ t a) = cupʟ (sglʟ (f φ)) (tree f a) tree f φ@(∃̇∈ t a) = cupʟ (sglʟ (f φ)) (tree f a) satTable : ∀ {n} → Formula S n → S satTable = tree ent slot : ∀ {n} → Formula S n → S slot = tree keyʟ
Reading the table back
Every member is one of the things gathered, which is the inversion the closure chapter needed in its own shape, and it is proved once for both. The two combinators take the inclusions rather than an equation between the two constructions, which is the rule that chapter measured.
Of : (f g : ∀ {m} → Formula S m → S) {n : ℕ} → Formula S n → V ℓ → Type (ℓ-suc ℓ) Of f g φ x = ∥ (Σ[ m ∈ ℕ ] Σ[ χ ∈ Formula S m ] ((x ≡ fst (f χ)) × ((z : V ℓ) → ⟨ z ∈ fst (tree g χ) ⟩ → ⟨ z ∈ fst (tree g φ) ⟩))) ∥₁ private module _ (f g : ∀ {m} → Formula S m → S) where one : ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (sglʟ (f φ)) ⟩ → Of f g φ x one {n} φ x h = ∣ n , φ , sglʟ-out (f φ) x h , (λ _ hz → hz) ∣₁ wider : ∀ {n m} (φ : Formula S n) (χ : Formula S m) {x : V ℓ} → ((z : V ℓ) → ⟨ z ∈ fst (tree g χ) ⟩ → ⟨ z ∈ fst (tree g φ) ⟩) → Of f g χ x → Of f g φ x wider _ _ s = PT.map (λ { (m , ψ , e , t) → m , ψ , e , (λ z hz → s z (t z hz)) }) un : ∀ {n m} (φ : Formula S n) (a : Formula S m) → ((z : V ℓ) → ⟨ z ∈ fst (cupʟ (sglʟ (g φ)) (tree g a)) ⟩ → ⟨ z ∈ fst (tree g φ) ⟩) → ((x : V ℓ) → ⟨ x ∈ fst (tree f a) ⟩ → Of f g a x) → (x : V ℓ) → ⟨ x ∈ fst (cupʟ (sglʟ (f φ)) (tree f a)) ⟩ → Of f g φ x un φ a into ra x h = PT.rec squash₁ (λ { (inl e) → one φ x e ; (inr e) → wider φ a (λ z hz → into z (cupʟ-inr (sglʟ (g φ)) (tree g a) z hz)) (ra x e) }) (cupʟ-out (sglʟ (f φ)) (tree f a) x h) bin : ∀ {n m} (φ : Formula S n) (a b : Formula S m) → ((z : V ℓ) → ⟨ z ∈ fst (cupʟ (sglʟ (g φ)) (cupʟ (tree g a) (tree g b))) ⟩ → ⟨ z ∈ fst (tree g φ) ⟩) → ((x : V ℓ) → ⟨ x ∈ fst (tree f a) ⟩ → Of f g a x) → ((x : V ℓ) → ⟨ x ∈ fst (tree f b) ⟩ → Of f g b x) → (x : V ℓ) → ⟨ x ∈ fst (cupʟ (sglʟ (f φ)) (cupʟ (tree f a) (tree f b))) ⟩ → Of f g φ x bin φ a b into ra rb x h = PT.rec squash₁ (λ { (inl e) → one φ x e ; (inr e) → PT.rec squash₁ (λ { (inl ea) → wider φ a (λ z hz → into z (cupʟ-inr (sglʟ (g φ)) (cupʟ (tree g a) (tree g b)) z (cupʟ-inl (tree g a) (tree g b) z hz))) (ra x ea) ; (inr eb) → wider φ b (λ z hz → into z (cupʟ-inr (sglʟ (g φ)) (cupʟ (tree g a) (tree g b)) z (cupʟ-inr (tree g a) (tree g b) z hz))) (rb x eb) }) (cupʟ-out (tree f a) (tree f b) x e) }) (cupʟ-out (sglʟ (f φ)) (cupʟ (tree f a) (tree f b)) x h) module Parts (f : ∀ {m} → Formula S m → S) where self : ∀ {n} (φ : Formula S n) → ⟨ fst (f φ) ∈ fst (tree f φ) ⟩ self φ@(t ∈̇ u) = sglʟ-in (f φ) _ refl self φ@(t ≐ u) = sglʟ-in (f φ) _ refl self φ@⊤̇ = sglʟ-in (f φ) _ refl self φ@⊥̇ = sglʟ-in (f φ) _ refl self φ@(a ∧̇ b) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(a ∨̇ b) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(a ⇒̇ b) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(¬̇ a) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(∃̇ a) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(∀̇ a) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(∀̇∈ t a) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) self φ@(∃̇∈ t a) = cupʟ-inl _ _ _ (sglʟ-in (f φ) _ refl) left : ∀ {n m} (χ : Formula S n) (a b : Formula S m) (z : V ℓ) → ⟨ z ∈ fst (tree f a) ⟩ → ⟨ z ∈ fst (cupʟ (sglʟ (f χ)) (cupʟ (tree f a) (tree f b))) ⟩ left χ a b z h = cupʟ-inr (sglʟ (f χ)) (cupʟ (tree f a) (tree f b)) z (cupʟ-inl (tree f a) (tree f b) z h) right : ∀ {n m} (χ : Formula S n) (a b : Formula S m) (z : V ℓ) → ⟨ z ∈ fst (tree f b) ⟩ → ⟨ z ∈ fst (cupʟ (sglʟ (f χ)) (cupʟ (tree f a) (tree f b))) ⟩ right χ a b z h = cupʟ-inr (sglʟ (f χ)) (cupʟ (tree f a) (tree f b)) z (cupʟ-inr (tree f a) (tree f b) z h) only : ∀ {n m} (χ : Formula S n) (a : Formula S m) (z : V ℓ) → ⟨ z ∈ fst (tree f a) ⟩ → ⟨ z ∈ fst (cupʟ (sglʟ (f χ)) (tree f a)) ⟩ only χ a z h = cupʟ-inr (sglʟ (f χ)) (tree f a) z h tree-inv : (f g : ∀ {m} → Formula S m → S) → ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (tree f φ) ⟩ → Of f g φ x tree-inv f g φ@(t ∈̇ u) = one f g φ tree-inv f g φ@(t ≐ u) = one f g φ tree-inv f g φ@⊤̇ = one f g φ tree-inv f g φ@⊥̇ = one f g φ tree-inv f g φ@(a ∧̇ b) = bin f g φ a b (λ _ hz → hz) (tree-inv f g a) (tree-inv f g b) tree-inv f g φ@(a ∨̇ b) = bin f g φ a b (λ _ hz → hz) (tree-inv f g a) (tree-inv f g b) tree-inv f g φ@(a ⇒̇ b) = bin f g φ a b (λ _ hz → hz) (tree-inv f g a) (tree-inv f g b) tree-inv f g φ@(¬̇ a) = un f g φ a (λ _ hz → hz) (tree-inv f g a) tree-inv f g φ@(∃̇ a) = un f g φ a (λ _ hz → hz) (tree-inv f g a) tree-inv f g φ@(∀̇ a) = un f g φ a (λ _ hz → hz) (tree-inv f g a) tree-inv f g φ@(∀̇∈ t a) = un f g φ a (λ _ hz → hz) (tree-inv f g a) tree-inv f g φ@(∃̇∈ t a) = un f g φ a (λ _ hz → hz) (tree-inv f g a) satTable-inv : ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (satTable φ) ⟩ → Of ent ent φ x satTable-inv = tree-inv ent ent slot-inv : ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (slot φ) ⟩ → Of keyʟ keyʟ φ x slot-inv = tree-inv keyʟ keyʟ slot-ent : ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (slot φ) ⟩ → Of keyʟ ent φ x slot-ent = tree-inv keyʟ ent ent-slot : ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (satTable φ) ⟩ → Of ent keyʟ φ x ent-slot = tree-inv ent keyʟ
A key determines its value
Two formulas with the same key have the same value, and that is where the code equation's injectivity is spent. The arities come out equal from the numeral half of the key, and the code equation from the other half; the first is then eliminated by path induction so that the second can be used at a single arity, which is the only arity at which it is true.
private same : ∀ {n} (ψ χ : Formula S n) → fst LCode.⌜ ψ ⌝ ≡ fst LCode.⌜ χ ⌝ → Sat B ψ ≡ Sat B χ same ψ χ e = cong (Sat B) (LCode.⌜⌝-inj ψ χ (Σ≡Prop (λ v → snd (isL v)) e)) cross : ∀ {n m} (ψ : Formula S n) (χ : Formula S m) → n ≡ m → fst LCode.⌜ ψ ⌝ ≡ fst LCode.⌜ χ ⌝ → Sat B ψ ≡ Sat B χ cross {n} ψ χ p = J (λ m' p' → (χ' : Formula S m') → fst LCode.⌜ ψ ⌝ ≡ fst LCode.⌜ χ' ⌝ → Sat B ψ ≡ Sat B χ') (same ψ) p χ total : ∀ {n} (φ : Formula S n) (x : V ℓ) → ⟨ x ∈ fst (slot φ) ⟩ → ∥ (Σ[ y ∈ S ] ⟨ pr x (fst y) ∈ fst (satTable φ) ⟩) ∥₁ total φ x h = PT.map (λ { (m , χ , (q , incl)) → Sat B χ , subst (λ w → ⟨ pr w (fst (Sat B χ)) ∈ fst (satTable φ) ⟩) (sym q) (incl (pr (fst (keyʟ χ)) (fst (Sat B χ))) (subst (λ w → ⟨ w ∈ fst (tree ent χ) ⟩) (prʟ-fst (keyʟ χ) (Sat B χ)) (Parts.self ent χ))) }) (slot-ent φ x h) inSlot : ∀ {n} (φ : Formula S n) (x y : V ℓ) → ⟨ pr x y ∈ fst (satTable φ) ⟩ → ⟨ x ∈ fst (slot φ) ⟩ inSlot φ x y h = PT.rec (snd (x ∈ fst (slot φ))) (λ { (m , χ , (q , incl)) → subst (λ w → ⟨ w ∈ fst (slot φ) ⟩) (sym (pr-inj (q ∙ prʟ-fst (keyʟ χ) (Sat B χ)) .fst)) (incl (fst (keyʟ χ)) (Parts.self keyʟ χ)) }) (ent-slot φ (pr x y) h) key-determines : ∀ {n m} (ψ : Formula S n) (χ : Formula S m) → fst (keyʟ ψ) ≡ fst (keyʟ χ) → Sat B ψ ≡ Sat B χ key-determines {n} {m} ψ χ e = cross ψ χ (#-inj′ (sym (numeralL-fst n) ∙ pr-inj q .fst ∙ numeralL-fst m)) (pr-inj q .snd) where q : pr (fst (numeralL n)) (fst LCode.⌜ ψ ⌝) ≡ pr (fst (numeralL m)) (fst LCode.⌜ χ ⌝) q = sym (prʟ-fst (numeralL n) LCode.⌜ ψ ⌝) ∙ e ∙ prʟ-fst (numeralL m) LCode.⌜ χ ⌝ entry-out : ∀ {n m} (φ : Formula S n) (ψ : Formula S m) (y : V ℓ) → ⟨ pr (fst (keyʟ ψ)) y ∈ fst (satTable φ) ⟩ → y ≡ fst (Sat B ψ) entry-out φ ψ y h = PT.rec (setIsSet y (fst (Sat B ψ))) (λ { (m , χ , (q , _)) → let r = pr-inj (q ∙ prʟ-fst (keyʟ χ) (Sat B χ)) in r .snd ∙ cong fst (sym (key-determines ψ χ (r .fst))) }) (satTable-inv φ (pr (fst (keyʟ ψ)) y) h) private top : ∀ {n} (φ : Formula S n) → ⟨ pr (fst (keyʟ φ)) (fst (Sat B φ)) ∈ fst (sglʟ (ent φ)) ⟩ top φ = sglʟ-in (ent φ) _ (sym (prʟ-fst (keyʟ φ) (Sat B φ))) slot-in : ∀ {n} (φ : Formula S n) → ⟨ fst (keyʟ φ) ∈ fst (slot φ) ⟩ slot-in = Parts.self keyʟ entry-in : ∀ {n} (φ : Formula S n) → ⟨ pr (fst (keyʟ φ)) (fst (Sat B φ)) ∈ fst (satTable φ) ⟩ entry-in φ@(t ∈̇ u) = top φ entry-in φ@(t ≐ u) = top φ entry-in φ@⊤̇ = top φ entry-in φ@⊥̇ = top φ entry-in φ@(a ∧̇ b) = cupʟ-inl _ _ _ (top φ) entry-in φ@(a ∨̇ b) = cupʟ-inl _ _ _ (top φ) entry-in φ@(a ⇒̇ b) = cupʟ-inl _ _ _ (top φ) entry-in φ@(¬̇ a) = cupʟ-inl _ _ _ (top φ) entry-in φ@(∃̇ a) = cupʟ-inl _ _ _ (top φ) entry-in φ@(∀̇ a) = cupʟ-inl _ _ _ (top φ) entry-in φ@(∀̇∈ t a) = cupʟ-inl _ _ _ (top φ) entry-in φ@(∃̇∈ t a) = cupʟ-inl _ _ _ (top φ)
What a key of a given tag has under it
The dispatch a clause performs, and the last piece before the twelve verifications. A clause is stated at a tag and receives a key of that shape; the formula the key names is recovered by the inversion above, and then its constructor has to be matched against the tag. That match is the coding chapter's own device, exported rather than rebuilt: the constructor is recoverable from the tag, so what a formula of a given tag looks like is computed from the tag, and the tag equation carries the formula's own case to it.
So one lemma serves all twelve clauses, and it hands back three things: what the formula's constructor is, that the arity read is the formula's, and that the payload read is the formula's.
keyʟ-shape-in : ∀ {m} (ψ : Formula S m) → fst (keyʟ ψ) ≡ pr (# m) (pr (# (LCode.tagOf ψ)) (fst (LCode.payOf ψ))) keyʟ-shape-in {m} ψ = prʟ-fst (numeralL m) LCode.⌜ ψ ⌝ ∙ cong₂ pr (numeralL-fst m) (cong fst (LCode.shape ψ) ∙ prʟ-fst (numeralL (LCode.tagOf ψ)) (LCode.payOf ψ) ∙ cong (λ w → pr w (fst (LCode.payOf ψ))) (numeralL-fst (LCode.tagOf ψ))) keyʟ-shape : ∀ {m} (ψ : Formula S m) (k : ℕ) (ar p : V ℓ) → fst (keyʟ ψ) ≡ pr ar (pr (# k) p) → LCode.Match k ψ × ((# m ≡ ar) × (fst (LCode.payOf ψ) ≡ p)) keyʟ-shape {m} ψ k ar p e = subst (λ j → LCode.Match j ψ) tag≡ (LCode.matches ψ) , ( sym (numeralL-fst m) ∙ pr-inj e' .fst , pr-inj inner .snd ) where e' : pr (fst (numeralL m)) (fst LCode.⌜ ψ ⌝) ≡ pr ar (pr (# k) p) e' = sym (prʟ-fst (numeralL m) LCode.⌜ ψ ⌝) ∙ e inner : pr (fst (numeralL (LCode.tagOf ψ))) (fst (LCode.payOf ψ)) ≡ pr (# k) p inner = sym (prʟ-fst (numeralL (LCode.tagOf ψ)) (LCode.payOf ψ)) ∙ sym (cong fst (LCode.shape ψ)) ∙ pr-inj e' .snd tag≡ : LCode.tagOf ψ ≡ k tag≡ = #-inj′ (sym (numeralL-fst (LCode.tagOf ψ)) ∙ pr-inj inner .fst)