Quantifying over coded pairs and finite formula families

Read this chapter directly, or use the reading guide and dependency map to choose another route.

Reading guide · Dependency map

This chapter supplies the shared finite-slot machinery used by coded formulas. It names deeply nested slots, folds finite families into conjunctions and disjunctions, and defines bounded formulas that unpack coded pairs together with readers that hide their container witnesses.

Coded syntax repeatedly quantifies over the components of a pair. Building on the coding vocabulary and pair expressions, this chapter develops the shared slot arithmetic, bounded formulas and semantic readers for those quantifiers. The tower specification uses these readers first; code-domain, satisfaction-clause and coded-graph chapters then reuse the same readers. Each can state its mathematics in terms of components without repeating the container witnesses required by bounded syntax.

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

open import Base.Prelude

module L.Coding.Quantification { : Level} where

open import FOL.ZFStructure using ( module hPropStructure )
open import FOL.Syntax using
  ( Formula; var; _∧̇_; _∨̇_; _⇒̇_; ∃̇∈; ∀̇∈ )
open import FOL.LevyHierarchy using
  ( Δ₀; δ-∧; δ-⇒; δ-∀∈; δ-∃∈ )
import FOL.Absoluteness
open import V.Hierarchy {} using ( 𝒮ᵥ )
open import V.Coding {} using ( pr )
open import L.Constructible {} using ( 𝒮ʟ; isL; isL-trans )
open import L.Absoluteness {} using ( Δ₀-liftFo )
open import L.Coding.PairFormulas {} using ( Δ₀-prAt; ∈pair-introL; ∈pair-introR )
open import L.Coding.Environment {} using ( Δ₀-sucAt )
open import L.Coding.Model {} using ( prAtL; prAtL-adequate )
open import L.Coding.Expressions {} using ( sucAtL; sucAtL-adequate )
open import L.Coding.Model {} using ( container )
import L.Coding.Expressions {} as CodingExpressions
module E = CodingExpressions.PairExpression

open import Cubical.Data.Nat using ( _+_ )
open import Cubical.Data.Vec using ( _∷_; lookup )
open import Cubical.Data.Sigma using ( _×_ )
open import Cubical.Data.Sum using ( inl; inr )
import Cubical.HITs.PropositionalTruncation as PT
open PT using ( ∥_∥₁; ∣_∣₁; squash₁ )
open import Cubical.HITs.CumulativeHierarchy.Base using ( V; _∈_ )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( ⁅_,_⁆; ⁅_⁆s; module InfinitySet )
open InfinitySet {} using ( sucV )

open hPropStructure 𝒮ʟ using ( S )

module AbsL = FOL.Absoluteness.Single 𝒮ᵥ isL isL-trans using ( _^_; _⊨ᵐ_ )
open AbsL using ( _^_ ) renaming ( _⊨ᵐ_ to _⊨_ )

Slot indices and primitive readers

The shift operation and named inner slots organize deeply nested binders, while the pair and successor readers turn their atomic formulas back into set equalities.

Slot arithmetic. sh k pushes an outer slot past k binders; the names i0 .. i19 are the innermost slots at any arity.

i0 :  {j}  Fin (suc j)
i0 = zero
i1 :  {j}  Fin (2 + j)
i1 = suc i0
i2 :  {j}  Fin (3 + j)
i2 = suc i1
i3 :  {j}  Fin (4 + j)
i3 = suc i2

pr-out :  {m} (q u v : Fin m) (γ : S ^ m)   γ  prAtL q u v 
        fst (lookup q γ)  pr (fst (lookup u γ)) (fst (lookup v γ))
pr-out q u v γ h = subst ⟨_⟩ (prAtL-adequate q u v γ) h

pr-in :  {m} (q u v : Fin m) (γ : S ^ m)
       fst (lookup q γ)  pr (fst (lookup u γ)) (fst (lookup v γ))
        γ  prAtL q u v 
pr-in q u v γ e = subst ⟨_⟩ (sym (prAtL-adequate q u v γ)) e

down : (x : S) (y : V )   y  fst x   S
down x y h = y , isL-trans {x = fst x} {y = y} h (snd x)

The components of a pair held as an element of L, as elements of L.

fstS sndS : (x : S) (u v : V )  fst x  pr u v  S
fstS x u v e = down (down x  u , v  (subst  z    u , v   z ) (sym e) (∈pair-introR {u =  u ⁆s} {v =  u , v } refl))) u (∈pair-introL {u = u} {v = v} refl)
sndS x u v e = down (down x  u , v  (subst  z    u , v   z ) (sym e) (∈pair-introR {u =  u ⁆s} {v =  u , v } refl))) v (∈pair-introR {u = u} {v = v} refl)
sh :  {m} (k : )  Fin m  Fin (k + m)
sh zero i = i
sh (suc k) i = suc (sh k i)

i4 :  {j}  Fin (5 + j)
i4 = suc i3
i5 :  {j}  Fin (6 + j)
i5 = suc i4
i6 :  {j}  Fin (7 + j)
i6 = suc i5
i7 :  {j}  Fin (8 + j)
i7 = suc i6
i8 :  {j}  Fin (9 + j)
i8 = suc i7
i9 :  {j}  Fin (10 + j)
i9 = suc i8
i10 :  {j}  Fin (11 + j)
i10 = suc i9
i11 :  {j}  Fin (12 + j)
i11 = suc i10
i12 :  {j}  Fin (13 + j)
i12 = suc i11
i13 :  {j}  Fin (14 + j)
i13 = suc i12
i14 :  {j}  Fin (15 + j)
i14 = suc i13
i15 :  {j}  Fin (16 + j)
i15 = suc i14
i16 :  {j}  Fin (17 + j)
i16 = suc i15
i17 :  {j}  Fin (18 + j)
i17 = suc i16
i18 :  {j}  Fin (19 + j)
i18 = suc i17
i19 :  {j}  Fin (20 + j)
i19 = suc i18

Ten named slots and finite connective folds

The patterns f0 through f9 name the ten positions used by constructor families, while bigOr and bigAnd fold any nonempty finite family of formulas. Their readers select one disjunct or recover every conjunct without depending on any particular coding scheme.

pattern f0 = zero
pattern f1 = suc f0
pattern f2 = suc f1
pattern f3 = suc f2
pattern f4 = suc f3
pattern f5 = suc f4
pattern f6 = suc f5
pattern f7 = suc f6
pattern f8 = suc f7
pattern f9 = suc f8

bigOr bigAnd :  {m} (n : )  (Fin (suc n)  Formula S m)  Formula S m
bigOr 0 φ = φ zero
bigOr (suc n) φ = φ zero ∨̇ bigOr n  k  φ (suc k))
bigAnd 0 φ = φ zero
bigAnd (suc n) φ = φ zero ∧̇ bigAnd n  k  φ (suc k))

module _ {m : } (γ : S ^ m) where
  bigOr-in : (n : ) (φ : Fin (suc n)  Formula S m) (k : Fin (suc n))
             γ  φ k    γ  bigOr n φ 
  bigOr-in 0 φ zero h = h
  bigOr-in (suc n) φ zero h =  inl h ∣₁
  bigOr-in (suc n) φ (suc k) h =  inr (bigOr-in n  j  φ (suc j)) k h) ∣₁

  bigOr-out : (n : ) (φ : Fin (suc n)  Formula S m)   γ  bigOr n φ 
              Σ[ k  Fin (suc n) ]  γ  φ k  ∥₁
  bigOr-out 0 φ h =  zero , h ∣₁
  bigOr-out (suc n) φ = PT.rec squash₁
     { (inl h)   zero , h ∣₁
       ; (inr h)  PT.map  { (k , hk)  suc k , hk }) (bigOr-out n  j  φ (suc j)) h) })

  bigAnd-in : (n : ) (φ : Fin (suc n)  Formula S m)
             ((k : Fin (suc n))   γ  φ k )   γ  bigAnd n φ 
  bigAnd-in 0 φ h = h zero
  bigAnd-in (suc n) φ h = h zero , bigAnd-in n  j  φ (suc j))  k  h (suc k))

  bigAnd-out : (n : ) (φ : Fin (suc n)  Formula S m)   γ  bigAnd n φ 
              (k : Fin (suc n))   γ  φ k 
  bigAnd-out 0 φ h zero = h
  bigAnd-out (suc n) φ h zero = h .fst
  bigAnd-out (suc n) φ h (suc k) = bigAnd-out n  j  φ (suc j)) (h .snd) k

Bounded atoms and successor semantics

The pair and successor atoms receive Δ₀ witnesses, and suc-out with suc-in gives the two semantic directions at a variable environment.

The atoms and their certificates.

Δ₀-prAtL :  {m} (q u v : Fin m)  Δ₀ (prAtL q u v)
Δ₀-prAtL q u v = Δ₀-liftFo _ (Δ₀-prAt q u v)

Δ₀-sucAtL :  {m} (i j : Fin m)  Δ₀ (sucAtL i j)
Δ₀-sucAtL i j = Δ₀-liftFo _ (Δ₀-sucAt i j)

The successor reader, both ways, at a variable environment.

suc-out :  {m} (i j : Fin m) (γ : S ^ m)   γ  sucAtL i j 
         fst (lookup j γ)  sucV (fst (lookup i γ))
suc-out i j γ h = subst ⟨_⟩ (sucAtL-adequate i j γ) h

suc-in :  {m} (i j : Fin m) (γ : S ^ m)
        fst (lookup j γ)  sucV (fst (lookup i γ))   γ  sucAtL i j 
suc-in i j γ e = subst ⟨_⟩ (sym (sucAtL-adequate i j γ)) e

Bounded quantifiers over pair components

The four macros sndEx, sndAll, bothEx, and bothAll bind pair components through an internal container, in existential and universal forms that remain Δ₀.

The pair as a container. Both components of pr u v lie in the member ⁅ u , v ⁆ of it. This is what lets a Δ₀ formula bind the components of a pair it holds, with no ambient bound at all.

The opaque pair container is supplied by L.Coding.Model and shared with its structural pair-expression reader.

The destructors. Four macros bind the components of a pair held at a slot: the second component alone (the first is a slot already), or both, each under an existential or a universal. The body sits at v ∷ s ∷ γ, or at v ∷ u ∷ s ∷ γ, with s the container. Every reader is at a variable environment; the container is junk the reader supplies.

sndEx :  {m}  Fin m  Fin m  Formula S (2 + m)  Formula S m
sndEx x u body =
  ∃̇∈ (var x) (∃̇∈ (var i0) (prAtL (sh 2 x) (sh 2 u) i0 ∧̇ body))

sndAll :  {m}  Fin m  Fin m  Formula S (2 + m)  Formula S m
sndAll x u body =
  ∀̇∈ (var x) (∀̇∈ (var i0) (prAtL (sh 2 x) (sh 2 u) i0 ⇒̇ body))

bothEx :  {m}  Fin m  Formula S (3 + m)  Formula S m
bothEx x body =
  ∃̇∈ (var x) (∃̇∈ (var i0) (∃̇∈ (var i1) (prAtL (sh 3 x) i1 i0 ∧̇ body)))

bothAll :  {m}  Fin m  Formula S (3 + m)  Formula S m
bothAll x body =
  ∀̇∈ (var x) (∀̇∈ (var i0) (∀̇∈ (var i1) (prAtL (sh 3 x) i1 i0 ⇒̇ body)))

Δ₀-sndEx :  {m} (x u : Fin m) (body : Formula S (2 + m))  Δ₀ body  Δ₀ (sndEx x u body)
Δ₀-sndEx x u body d = δ-∃∈ (δ-∃∈ (δ-∧ (Δ₀-prAtL (sh 2 x) (sh 2 u) i0) d))

Δ₀-sndAll :  {m} (x u : Fin m) (body : Formula S (2 + m))  Δ₀ body  Δ₀ (sndAll x u body)
Δ₀-sndAll x u body d = δ-∀∈ (δ-∀∈ (δ-⇒ (Δ₀-prAtL (sh 2 x) (sh 2 u) i0) d))

Δ₀-bothAll :  {m} (x : Fin m) (body : Formula S (3 + m))  Δ₀ body  Δ₀ (bothAll x body)
Δ₀-bothAll x body d = δ-∀∈ (δ-∀∈ (δ-∀∈ (δ-⇒ (Δ₀-prAtL (sh 3 x) i1 i0) d)))

module _ {m : } (x u : Fin m) (body : Formula S (2 + m)) (γ : S ^ m) where
  private
    X = fst (lookup x γ)
    U = fst (lookup u γ)

Reading the component quantifiers

The existential out lemmas return the propositional truncation of component data, recording that suitable components merely exist; the universal readers instead accept explicit components. The corresponding in lemmas rebuild satisfaction from explicit data, using pair injectivity to pin the values.

Out: the witness's second component is pinned by pair injectivity.

  sndEx-out :  γ  sndEx x u body 
              Σ[ v  S ] Σ[ s  S ] ((X  pr U (fst v)) ×  (v  s  γ)  body ) ∥₁
  sndEx-out = PT.rec squash₁  { (s , (s∈ , h))  PT.map
     { (v , (v∈ , (e , hb)))  v , s , (pr-out (sh 2 x) (sh 2 u) i0 (v  s  γ) e , hb) })
    h })

  sndEx-in : (v s : S)   fst s  X    fst v  fst s   X  pr U (fst v)
             (v  s  γ)  body    γ  sndEx x u body 
  sndEx-in v s s∈ v∈ e hb =  s , (s∈ ,  v , (v∈ , (pr-in (sh 2 x) (sh 2 u) i0 (v  s  γ) e , hb)) ∣₁) ∣₁

  sndAll-out :  γ  sndAll x u body 
              (v s : S)   fst s  X    fst v  fst s   X  pr U (fst v)
               (v  s  γ)  body 
  sndAll-out h v s s∈ v∈ e = h s s∈ v v∈ (pr-in (sh 2 x) (sh 2 u) i0 (v  s  γ) e)

  sndAll-in : ((v s : S)   fst s  X    fst v  fst s   X  pr U (fst v)
                 (v  s  γ)  body )
              γ  sndAll x u body 
  sndAll-in k s s∈ v v∈ e = k v s s∈ v∈ (pr-out (sh 2 x) (sh 2 u) i0 (v  s  γ) e)

module _ {m : } (x : Fin m) (body : Formula S (3 + m)) (γ : S ^ m) where
  private
    X = fst (lookup x γ)

  bothEx-out :  γ  bothEx x body 
               Σ[ u  S ] Σ[ v  S ] Σ[ s  S ]
                 ((X  pr (fst u) (fst v)) ×  (v  u  s  γ)  body ) ∥₁
  bothEx-out = PT.rec squash₁  { (s , (s∈ , h))  PT.rec squash₁
     { (u , (u∈ , h'))  PT.map
       { (v , (v∈ , (e , hb)))  u , v , s , (pr-out (sh 3 x) i1 i0 (v  u  s  γ) e , hb) })
      h' })
    h })

  bothEx-in : (u v s : S)   fst s  X    fst u  fst s    fst v  fst s 
             X  pr (fst u) (fst v)   (v  u  s  γ)  body    γ  bothEx x body 
  bothEx-in u v s s∈ u∈ v∈ e hb =
     s , (s∈ ,  u , (u∈ ,  v , (v∈ , (pr-in (sh 3 x) i1 i0 (v  u  s  γ) e , hb)) ∣₁) ∣₁) ∣₁

  bothAll-out :  γ  bothAll x body 
               (u v s : S)   fst s  X    fst u  fst s    fst v  fst s 
               X  pr (fst u) (fst v)   (v  u  s  γ)  body 
  bothAll-out h u v s s∈ u∈ v∈ e = h s s∈ u u∈ v v∈ (pr-in (sh 3 x) i1 i0 (v  u  s  γ) e)

  bothAll-in : ((u v s : S)   fst s  X    fst u  fst s    fst v  fst s 
                 X  pr (fst u) (fst v)   (v  u  s  γ)  body )
               γ  bothAll x body 
  bothAll-in k s s∈ u u∈ v v∈ e = k u v s s∈ u∈ v∈ (pr-out (sh 3 x) i1 i0 (v  u  s  γ) e)

Supplying the container witnesses

fillSnd, fillBoth, useSnd, and useBoth construct the internal container automatically from a pair equality, leaving callers to reason only about its components.

Supplying the junk: a pair at a slot, with its components as elements, fills any of the four.

module _ {m : } (x : Fin m) (γ : S ^ m) (u v : S)
         (e : fst (lookup x γ)  pr (fst u) (fst v)) where
  private
    c = container (lookup x γ) u v e

  fillSnd : (body : Formula S (2 + m))   (v  c .fst  γ)  body 
           (ui : Fin m)  fst (lookup ui γ)  fst u   γ  sndEx x ui body 
  fillSnd body hb ui qu = sndEx-in x ui body γ v (c .fst) (c .snd .fst) (c .snd .snd .snd)
    (e  cong  w  pr w (fst v)) (sym qu)) hb

  fillBoth : (body : Formula S (3 + m))   (v  u  c .fst  γ)  body 
             γ  bothEx x body 
  fillBoth body hb = bothEx-in x body γ u v (c .fst) (c .snd .fst) (c .snd .snd .fst)
    (c .snd .snd .snd) e hb

  useSnd : (body : Formula S (2 + m)) (ui : Fin m)  fst (lookup ui γ)  fst u
           γ  sndAll x ui body    (v  c .fst  γ)  body 
  useSnd body ui qu h = sndAll-out x ui body γ h v (c .fst) (c .snd .fst) (c .snd .snd .snd)
    (e  cong  w  pr w (fst v)) (sym qu))

  useBoth : (body : Formula S (3 + m))   γ  bothAll x body 
            (v  u  c .fst  γ)  body 
  useBoth body h = bothAll-out x body γ h u v (c .fst) (c .snd .fst) (c .snd .snd .fst)
    (c .snd .snd .snd) e

Recap

The named slots and finite connective folds organize repeated formula families. The bounded pair formulas expose one or both components of a coded pair, their readers recover the component semantics, and the filling lemmas hide the container witnesses needed when those readers are reused in larger formulas.