Smallness

The previous chapter ended on a warning about universes: V ℓ is a large type built from small indexing data, and its truth values live in hProp (ℓ-suc ℓ), one level up. The warning matters because every set-forming device the library offers, sett first among them, accepts only small input: a small index type, a small predicate. To build a set out of a property, the property's truth value must first be brought down a universe. This chapter builds the toolkit for exactly that, and its payoff is the part's first theorem worth framing: separation for Δ₀ formulas costs no axiom at all.

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

open import Base.Prelude
open import Base.Truth

module V.Smallness { : Level} where

open import Base.Impredicativity using ( isSmall )
open import FOL.ZFStructure using ( ZFStructure; _↾_ )
open import FOL.Syntax
  using ( Formula; _∈̇_; _≐_; _∧̇_; _∨̇_; _⇒̇_; ¬̇_; ⊤̇; ⊥̇; ∃̇_; ∀̇_; ∀̇∈; ∃̇∈ )
open import FOL.LevyHierarchy
  using ( Δ₀; δ-∈; δ-≐; δ-∧; δ-∨; δ-⇒; δ-¬; δ-⊤; δ-⊥; δ-∀∈; δ-∃∈ )
import FOL.Semantics
open import V.Hierarchy {} using ( 𝒮ᵥ )

open import Cubical.Foundations.Equiv
  using ( _≃_; equivFun; invEq; invEquiv; secEq; propBiimpl→Equiv )
import Cubical.Functions.Logic as Logic
open import Cubical.Functions.Logic using ( ⇔toPath )
import Cubical.Data.Sum as Sum
open import Cubical.Data.Unit using ( tt* )
import Cubical.HITs.PropositionalTruncation as PT
open import Cubical.HITs.CumulativeHierarchy.Properties
  using ( _∼_; identityPrinciple; _∈ₛ_; ∈∈ₛ; ⟪_⟫; ⟪_⟫↪; ∈ₛ⟪_⟫↪_; ∈-asFiber )
open import Cubical.HITs.CumulativeHierarchy.Constructions
  using ( module SeparationSet )

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

Being small

A proposition one universe up is small when it is equivalent to some proposition one universe down: the definition (isSmall) was minted in Part 0, where the resizing interface asserts it of every proposition wholesale. This chapter assumes no such thing. It earns instances, one atom at a time, and the whole chapter is an exercise in passing the earned witnesses around.

The atoms are small straight from the library. This is the local-smallness apparatus the previous chapter glimpsed: membership has a small twin ∈ₛ (∈∈ₛ converts back and forth), and equality of sets compresses to the bisimilarity through identityPrinciple.

small-∈ : (a b : S)  isSmall (a ∈ˢ b)
small-∈ a b = (a ∈ₛ b) ,
  propBiimpl→Equiv (snd (a ∈ˢ b)) (snd (a ∈ₛ b))
    (∈∈ₛ {a = a} {b = b} .fst) (∈∈ₛ {a = a} {b = b} .snd)

small-≡ : (a b : S)  isSmall (a ≈ˢ b)
small-≡ a b = (a  b) , invEquiv identityPrinciple

The connectives preserve smallness

Each of the six propositional operations passes smallness witnesses through; each proof is the mechanical transport of a bi-implication. (The qualified

Logic names are the library's connectives at the lower level, the codomain of the compression.)

small⊓ : {P Q : hProp (ℓ-suc )}  isSmall P  isSmall Q  isSmall (P  Q)
small⊓ {P} {Q} (P' , eP) (Q' , eQ) = (P' Logic.⊓ Q') ,
  propBiimpl→Equiv (snd (P  Q)) (snd (P' Logic.⊓ Q'))
     pq  equivFun eP (pq .fst) , equivFun eQ (pq .snd))
     pq  invEq eP (pq .fst) , invEq eQ (pq .snd))

small⊔ : {P Q : hProp (ℓ-suc )}  isSmall P  isSmall Q  isSmall (P  Q)
small⊔ {P} {Q} (P' , eP) (Q' , eQ) = (P' Logic.⊔ Q') ,
  propBiimpl→Equiv (snd (P  Q)) (snd (P' Logic.⊔ Q'))
    (PT.map (Sum.map (equivFun eP) (equivFun eQ)))
    (PT.map (Sum.map (invEq eP) (invEq eQ)))

small⇒ : {P Q : hProp (ℓ-suc )}  isSmall P  isSmall Q  isSmall (P  Q)
small⇒ {P} {Q} (P' , eP) (Q' , eQ) = (P' Logic.⇒ Q') ,
  propBiimpl→Equiv (snd (P  Q)) (snd (P' Logic.⇒ Q'))
     f p'  equivFun eQ (f (invEq eP p')))
     g p  invEq eQ (g (equivFun eP p)))

small¬ : {P : hProp (ℓ-suc )}  isSmall P  isSmall (¬ P)
small¬ {P} (P' , eP) = (Logic.¬ P') ,
  propBiimpl→Equiv (snd (¬ P)) (snd (Logic.¬ P'))
     np p'  np (invEq eP p'))
     np' p  np' (equivFun eP p))

small⊤ : isSmall 
small⊤ = Logic.⊤ ,
  propBiimpl→Equiv ( .snd) (snd (Logic.⊤ {}))
     _  tt*)  _  tt*)

small⊥ : isSmall 
small⊥ = (⊥* , isProp⊥*) ,
  propBiimpl→Equiv isProp⊥* isProp⊥*  ())  ())

Bounded quantifiers preserve smallness

Here is the load-bearing step, and the point where the syntax chapter's oldest promise pays off in the currency of universes. A quantifier over all of V ℓ ranges over a large type and has no reason to be small. A quantifier bounded by a set a can instead range over the library's small member type ⟪ a ⟫, the index type of a's family, and smallness survives. The two directions travel along ∈-asFiber, whose fibers are untruncated because ⟪ a ⟫↪ is an embedding: passing from "a member of a" back to "an index of ⟪ a ⟫" is a function, not a choice.

small-∀∈ : (a : S) {B : S  hProp (ℓ-suc )}
          (∀ x  isSmall (B x))
          isSmall ( S  x  (x ∈ˢ a)  B x))
small-∀∈ a {B} sm = Qsm , propBiimpl→Equiv (snd big) (snd Qsm) fwd bwd
  where
  big =  S  x  (x ∈ˢ a)  B x)
  Qsm = Logic.∀[]-syntax  (m :  a )  sm ( a ⟫↪ m) .fst)
  fwd :  big    Qsm 
  fwd f m = equivFun (sm ( a ⟫↪ m) .snd)
                     (f ( a ⟫↪ m) (∈∈ₛ {a =  a ⟫↪ m} {b = a} .snd (∈ₛ⟪ a ⟫↪ m)))
  bwd :  Qsm    big 
  bwd g x x∈a =
    subst  v   B v ) (mf .snd)
          (invEq (sm ( a ⟫↪ (mf .fst)) .snd) (g (mf .fst)))
    where mf = ∈-asFiber {a = x} {b = a} x∈a

small-∃∈ : (a : S) {B : S  hProp (ℓ-suc )}
          (∀ x  isSmall (B x))
          isSmall ( S  x  (x ∈ˢ a)  B x))
small-∃∈ a {B} sm = Qsm , propBiimpl→Equiv (snd big) (snd Qsm) fwd bwd
  where
  big =  S  x  (x ∈ˢ a)  B x)
  Qsm = Logic.∃[]-syntax  (m :  a )  sm ( a ⟫↪ m) .fst)
  fwd :  big    Qsm 
  fwd = PT.map λ where
    (x , x∈a , bx) 
      let mf = ∈-asFiber {a = x} {b = a} x∈a
      in mf .fst ,
         equivFun (sm ( a ⟫↪ (mf .fst)) .snd)
                  (subst  v   B v ) (sym (mf .snd)) bx)
  bwd :  Qsm    big 
  bwd = PT.map λ where
    (m , q)   a ⟫↪ m , ∈∈ₛ {a =  a ⟫↪ m} {b = a} .snd (∈ₛ⟪ a ⟫↪ m)
            , invEq (sm ( a ⟫↪ m) .snd) q

The separation pipe

What smallness buys: a pointwise-small predicate can be separated. The library's

SeparationSet accepts only small predicates, and a smallness witness is exactly the ticket in; the specification comes back in the model record's field shape. Every separation this part performs, whatever pays for the smallness, flows through this one pipe.

separateFromSmall : (a : S) (P : S  hProp (ℓ-suc ))
                   (∀ y  isSmall (P y))
                   Σ[ s  S ] (∀ y  (y ∈ˢ s)  ((y ∈ˢ a)  P y))
separateFromSmall a P sm = Sep.SEPAREE , λ y  ⇔toPath (fwd y) (bwd y)
  where
  ϕₛ : S  hProp 
  ϕₛ y = sm y .fst
  module Sep = SeparationSet a ϕₛ
  fwd :  y   y ∈ˢ Sep.SEPAREE    (y ∈ˢ a)  P y 
  fwd y y∈s = ∈∈ₛ {a = y} {b = a} .snd (Sep.separation-ax y .fst y∈ₛs .fst)
            , invEq (sm y .snd) (Sep.separation-ax y .fst y∈ₛs .snd)
    where y∈ₛs = ∈∈ₛ {a = y} {b = Sep.SEPAREE} .fst y∈s
  bwd :  y   (y ∈ˢ a)  P y    y ∈ˢ Sep.SEPAREE 
  bwd y yp = ∈∈ₛ {a = y} {b = Sep.SEPAREE} .snd (Sep.separation-ax y .snd
               (∈∈ₛ {a = y} {b = a} .fst (yp .fst) , equivFun (sm y .snd) (yp .snd)))

Δ₀ formulas evaluate small

Now the Δ₀ witnesses earn a second salary. One induction over the Δ₀ witness shows that the witnessed formula's truth value at any environment is small: the two atoms are the library compressions, the eight connective cases are the closure lemmas, and the two bounded-quantifier cases consume

small-∀∈ and small-∃∈. There is no case for the unbounded quantifiers, because the witness has no such constructors: absence is the classification. This is the second load-bearing induction over Δ₀ witnesses (absoluteness was the first), and it is why the Levy hierarchy doubles as a cost accounting: Δ₀ means free, in the precise sense of universe levels.

module SemanticsV = FOL.Semantics (hPropAlgebra (ℓ-suc )) 𝒮ᵥ
open SemanticsV using ( _^_ )

module Δ₀Small {ℓc} {K : Type ℓc} (ι : K  S) where

  open SemanticsV.At K ι

  Δ₀-small :  {n} {φ : Formula K n}  Δ₀ φ  (γ : S ^ n)  isSmall (γ  φ)
  Δ₀-small (δ-∈ {t = t} {u}) γ = small-∈ ( t  γ) ( u  γ)
  Δ₀-small (δ-≐ {t = t} {u}) γ = small-≡ ( t  γ) ( u  γ)
  Δ₀-small (δ-∧ {φ = φ} {ψ} c d) γ =
    small⊓ {P = γ  φ} {Q = γ  ψ} (Δ₀-small c γ) (Δ₀-small d γ)
  Δ₀-small (δ-∨ {φ = φ} {ψ} c d) γ =
    small⊔ {P = γ  φ} {Q = γ  ψ} (Δ₀-small c γ) (Δ₀-small d γ)
  Δ₀-small (δ-⇒ {φ = φ} {ψ} c d) γ =
    small⇒ {P = γ  φ} {Q = γ  ψ} (Δ₀-small c γ) (Δ₀-small d γ)
  Δ₀-small (δ-¬ {φ = φ} c) γ = small¬ {P = γ  φ} (Δ₀-small c γ)
  Δ₀-small δ-⊤ γ = small⊤
  Δ₀-small δ-⊥ γ = small⊥
  Δ₀-small (δ-∀∈ {t = t} {φ = φ} c) γ =
    small-∀∈ ( t  γ) {B = λ x  (x  γ)  φ}  x  Δ₀-small c (x  γ))
  Δ₀-small (δ-∃∈ {t = t} {φ = φ} c) γ =
    small-∃∈ ( t  γ) {B = λ x  (x  γ)  φ}  x  Δ₀-small c (x  γ))

The theorem: Δ₀ separation is free

Compose the induction with the pipe, at the canonical constant interpretation, and the flagship falls out: a formula carrying a Δ₀ witness can be separated with no resizing and no axiom, --safe all the way down. The model chapter will still owe full separation, but this theorem is the first hard evidence for a running theme: the Δ₀ witnesses are portable assets, and carrying them pays.

open Δ₀Small id
open SemanticsV.At S id using ( _⊨_ )

separateΔ₀ : (a : S) (φ : Formula S 1)  Δ₀ φ
            Σ[ s  S ] (∀ y  (y ∈ˢ s)  ((y ∈ˢ a)  ((y  [])  φ)))
separateΔ₀ a φ c = separateFromSmall a  y  (y  [])  φ)  y  Δ₀-small c (y  []))

Essentially small worlds

One more register of smallness, bought not by Δ₀ witnesses but by location. When the quantification range is itself equivalent to a small type, even the unbounded quantifiers preserve smallness: quantify along the equivalence. This does not contradict the cost accounting above, which priced quantifiers ranging over all of V ℓ; here the range is the carrier of a restricted structure 𝒮ᵥ ↾ M, and smallness is exactly what the restriction buys.

small-⋀ : {A : Type (ℓ-suc )} {X : Type } (e : X  A) {B : A  hProp (ℓ-suc )}
         (∀ a  isSmall (B a))
         isSmall ( A B)
small-⋀ {A} {X} e {B} sm = Qsm , propBiimpl→Equiv (snd big) (snd Qsm) fwd bwd
  where
  big =  A B
  Qsm = Logic.∀[]-syntax  (m : X)  sm (equivFun e m) .fst)
  fwd :  big    Qsm 
  fwd f m = equivFun (sm (equivFun e m) .snd) (f (equivFun e m))
  bwd :  Qsm    big 
  bwd g a = subst  v   B v ) (secEq e a)
                  (invEq (sm (equivFun e (invEq e a)) .snd) (g (invEq e a)))

small-⋁ : {A : Type (ℓ-suc )} {X : Type } (e : X  A) {B : A  hProp (ℓ-suc )}
         (∀ a  isSmall (B a))
         isSmall ( A B)
small-⋁ {A} {X} e {B} sm = Qsm , propBiimpl→Equiv (snd big) (snd Qsm) fwd bwd
  where
  big =  A B
  Qsm = Logic.∃[]-syntax  (m : X)  sm (equivFun e m) .fst)
  fwd :  big    Qsm 
  fwd = PT.map λ where
    (a , ba)  invEq e a ,
               equivFun (sm (equivFun e (invEq e a)) .snd)
                        (subst  v   B v ) (sym (secEq e a)) ba)
  bwd :  Qsm    big 
  bwd = PT.map λ where
    (m , q)  equivFun e m , invEq (sm (equivFun e m) .snd) q

The consequence: over an essentially small restricted structure, every formula evaluates small, no Δ₀ witness required. The quantifier clauses walk along the equivalence, the atoms drop back to V's atomic smallness through the first projection. This is "spoken inside a small world, everything said is small", and it is the engine of Part 4's single construction step.

module InnerSmall (M : S  hProp (ℓ-suc ))
                  (X : Type ) (e : X  (Σ[ x  S ] (x ∈ᶜ M)))
                  {ℓc} {K : Type ℓc}
                  (ι : K  Σ[ x  S ] (x ∈ᶜ M)) where

  SM : Type (ℓ-suc )
  SM = Σ[ x  S ] (x ∈ᶜ M)

  𝒮M : ZFStructure (hPropAlgebra (ℓ-suc ))
  𝒮M = 𝒮ᵥ  M

  module SemanticsM = FOL.Semantics (hPropAlgebra (ℓ-suc )) 𝒮M
  open SemanticsM.At K ι renaming ( _⊨_ to _⊨ᵐ_ ; ⟦_⟧ to ⟦_⟧ᵐ ) public

  ⊨ᵐ-small :  {n} (φ : Formula K n) (δ : SM ^ n)  isSmall (δ ⊨ᵐ φ)
  ⊨ᵐ-small (t ∈̇ u)  δ = small-∈ (fst ( t ⟧ᵐ δ)) (fst ( u ⟧ᵐ δ))
  ⊨ᵐ-small (t  u)  δ = small-≡ (fst ( t ⟧ᵐ δ)) (fst ( u ⟧ᵐ δ))
  ⊨ᵐ-small (φ ∧̇ ψ)  δ =
    small⊓ {P = δ ⊨ᵐ φ} {Q = δ ⊨ᵐ ψ} (⊨ᵐ-small φ δ) (⊨ᵐ-small ψ δ)
  ⊨ᵐ-small (φ ∨̇ ψ)  δ =
    small⊔ {P = δ ⊨ᵐ φ} {Q = δ ⊨ᵐ ψ} (⊨ᵐ-small φ δ) (⊨ᵐ-small ψ δ)
  ⊨ᵐ-small (φ ⇒̇ ψ)  δ =
    small⇒ {P = δ ⊨ᵐ φ} {Q = δ ⊨ᵐ ψ} (⊨ᵐ-small φ δ) (⊨ᵐ-small ψ δ)
  ⊨ᵐ-small (¬̇ φ)    δ = small¬ {P = δ ⊨ᵐ φ} (⊨ᵐ-small φ δ)
  ⊨ᵐ-small ⊤̇        δ = small⊤
  ⊨ᵐ-small ⊥̇        δ = small⊥
  ⊨ᵐ-small (∃̇ φ)    δ =
    small-⋁ e {B = λ xm  (xm  δ) ⊨ᵐ φ}  xm  ⊨ᵐ-small φ (xm  δ))
  ⊨ᵐ-small (∀̇ φ)    δ =
    small-⋀ e {B = λ xm  (xm  δ) ⊨ᵐ φ}  xm  ⊨ᵐ-small φ (xm  δ))
  ⊨ᵐ-small (∀̇∈ t φ) δ =
    small-⋀ e {B = λ xm  (fst xm ∈ˢ fst ( t ⟧ᵐ δ))  ((xm  δ) ⊨ᵐ φ)}  xm 
      small⇒ {P = fst xm ∈ˢ fst ( t ⟧ᵐ δ)} {Q = (xm  δ) ⊨ᵐ φ}
        (small-∈ (fst xm) (fst ( t ⟧ᵐ δ))) (⊨ᵐ-small φ (xm  δ)))
  ⊨ᵐ-small (∃̇∈ t φ) δ =
    small-⋁ e {B = λ xm  (fst xm ∈ˢ fst ( t ⟧ᵐ δ))  ((xm  δ) ⊨ᵐ φ)}  xm 
      small⊓ {P = fst xm ∈ˢ fst ( t ⟧ᵐ δ)} {Q = (xm  δ) ⊨ᵐ φ}
        (small-∈ (fst xm) (fst ( t ⟧ᵐ δ))) (⊨ᵐ-small φ (xm  δ)))

Recap

Smallness is equivalence to a proposition one universe down (isSmall); the atoms compress through the library, the connectives and the bounded quantifiers pass smallness witnesses along, and separateFromSmall is the one pipe from small predicates to sets. The induction Δ₀-small then makes the Levy hierarchy a cost accounting, with separateΔ₀ as the free tier. What Δ₀ cannot reach is priced in the model chapter, and the price has a name: resizing.