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)