module 1Lab.Resizing where

Propositional resizing🔗

Ordinarily, the collection of all predicates on types lives in the next universe up, This is because predicates are not special in type theory: they are ordinary type families, that just so happen to be valued in propositions. For most purposes we can work with this limitation: this is called predicative mathematics. But, for a few classes of theorems, predicativity is too restrictive: Even if we don’t have a single universe of propositions that can accommodate all predicates, we would still like for universes to be closed under power-sets.

Using some of Agda’s more suspicious features, we can achieve this in a way which does not break computation too much. Specifically, we’ll use a combination of NO_UNIVERSE_CHECK, postulates, and rewrite rules.

We start with the NO_UNIVERSE_CHECK part: We define the small type of propositions, Ω, to be a record containing a Type (together with an irrelevant proof that this type is a proposition), but contrary to the universe checker, which would like us to put Ω : Type₁, we instead force Ω : Type.

{-# NO_UNIVERSE_CHECK #-}
record Ω : Type where
  constructor el
  field
    ∣_∣   : Type
    is-tr : is-prop ∣_∣
open Ω public

This type, a priori, only contains the propositions whose underlying type lives in the first universe. However, we can populate it using a NO_UNIVERSE_CHECK-powered higher inductive type, the “small propositional truncation”:

{-# NO_UNIVERSE_CHECK #-}
data  {} (A : Type ) : Type where
  inc    : A   A
  squash : (x y :  A)  x  y

Just like the ordinary propositional truncation, every type can be squashed, but unlike the ordinary propositional truncation, the -squashing of a type always lives in the lowest universe. If is a proposition in any universe, is its name in the zeroth universe.

We can also prove a univalence principle for Ω: if are logically equivalent, then they are equal.

Ω-ua : {A B : Ω}   A    B   A  B
Ω-ua {A} {B} f i .∣_∣ = ua (prop-ext! (Biimp.to f) (Biimp.from f)) i
Ω-ua {A} {B} f i .is-tr =
  is-prop→pathp  i  is-prop-is-prop {A = ua (prop-ext! (Biimp.to f) (Biimp.from f)) i})
    (A .is-tr) (B .is-tr) i

instance abstract
  H-Level-Ω :  {n}  H-Level Ω (2 + n)
  H-Level-Ω = basic-instance 2 $ retract→is-hlevel 2
     r  el  r  (r .is-tr))
     r  el  r  (r .is-tr))
     x  Ω-ua id↔)
    (n-Type-is-hlevel {lzero} 1)

The type former is a functor (in the handwavy sense that it supports a “map” operation), and can be projected from into propositions of any universe. These functions compute on incs, as usual.

□-map :  { ℓ'} {A : Type } {B : Type ℓ'}
       (A  B)   A   B
□-map f (inc x) = inc (f x)
□-map f (squash x y i) = squash (□-map f x) (□-map f y) i

□-rec :  { ℓ'} {A : Type } {B : Type ℓ'}  is-prop B  (A  B)   A  B
□-rec bp f (inc x)        = f x
□-rec bp f (squash x y i) = bp (□-rec bp f x) (□-rec bp f y) i

elΩ :  {} (T : Type )  Ω
elΩ T .∣_∣ =  T
elΩ T .is-tr = squash
□-elim
  :  { ℓ'} {A : Type } {P :  A  Type ℓ'}
   (∀ x  is-prop (P x))
   (∀ x  P (inc x))
    x  P x
□-elim pprop go (inc x) = go x
□-elim pprop go (squash x y i) =
  is-prop→pathp  i  pprop (squash x y i)) (□-elim pprop go x) (□-elim pprop go y) i

instance
  Inductive-□
    :  { ℓ' ℓm} {A : Type } {P :  A  Type ℓ'}  i : Inductive (∀ x  P (inc x)) ℓm 
      _ :  {x}  H-Level (P x) 1 
     Inductive (∀ x  P x) ℓm
  Inductive-□  i  = record
    { methods = i .Inductive.methods
    ; from    = λ f  □-elim  x  hlevel 1) (i .Inductive.from f)
    }

□-out :  {} {A : Type }  is-prop A   A  A
□-out ap = □-rec ap  x  x)

□-out!
  :  {} {A : Type }
    _ : H-Level A 1 
    A  A
□-out! = rec! λ x  x

□-rec-set
  :  { ℓ'} {A : Type } {B : Type ℓ'}
   is-set B
   (f : A  B)
   (∀ x y  f x  f y)
    A  B
□-rec-set B-set f f-const a =
  fst $ □-elim
     _  is-constant→image-is-prop B-set f f-const)
     a  f a , inc (a , refl))
    a

□-idempotent :  {} {A : Type }  is-prop A   A  A
□-idempotent aprop = prop-ext squash aprop (□-out aprop) inc

□-ap
  :  { ℓ'} {A : Type } {B : Type ℓ'}
    (A  B)   A   B
□-ap (inc f) (inc g) = inc (f g)
□-ap (inc f) (squash g g' i) = squash (□-ap (inc f) g) (□-ap (inc f) g') i
□-ap (squash f f' i) g = squash (□-ap f g) (□-ap f' g) i

□-bind
  :  { ℓ'} {A : Type } {B : Type ℓ'}
    A  (A   B)   B
□-bind (inc x) f = f x
□-bind (squash x x' i) f = squash (□-bind x f) (□-bind x' f) i

instance
  Map-□ : Map (eff )
  Map-□ .Map.map = □-map

  Idiom-□ : Idiom (eff )
  Idiom-□ .Idiom.pure = inc
  Idiom-□ .Idiom._<*>_ = □-ap

  Bind-□ : Bind (eff )
  Bind-□ .Bind._>>=_ = □-bind

is-set→locally-small
  :  {} {A : Type }
   is-set A
   is-identity-system {A = A}  x y   (x  y))  x  inc refl)
is-set→locally-small a-set .to-path = □-rec (a-set _ _) id
is-set→locally-small a-set .to-path-over p = is-prop→pathp  _  squash) _ _

to-is-true
  :  {P Q : Ω}  _ : H-Level  Q  0 
    P 
   P  Q
to-is-true prf = Ω-ua (biimp  _  hlevel 0 .centre) λ _  prf)

tr-□ :  {} {A : Type }   A    A
tr-□ (inc x) = inc x
tr-□ (squash x y i) = squash (tr-□ x) (tr-□ y) i

□-tr :  {} {A : Type }   A   A 
□-tr (inc x) = inc x
□-tr (squash x y i) = squash (□-tr x) (□-tr y) i

Connectives🔗

The universe of small propositions contains true, false, conjunctions, disjunctions, and (bi)implications.

⊤Ω : Ω
 ⊤Ω  = 
⊤Ω .is-tr = hlevel 1

⊥Ω : Ω
 ⊥Ω  = 
⊥Ω .is-tr = hlevel 1

_∧Ω_ : Ω  Ω  Ω
 P ∧Ω Q  =  P  ×  Q 
(P ∧Ω Q) .is-tr = hlevel 1

_∨Ω_ : Ω  Ω  Ω
 P ∨Ω Q  =   P    Q  
(P ∨Ω Q) .is-tr = hlevel 1

_→Ω_ : Ω  Ω  Ω
 P →Ω Q  =  P    Q 
(P →Ω Q) .is-tr = hlevel 1

_↔Ω_ : Ω  Ω  Ω
 P ↔Ω Q  =  P    Q 
(P ↔Ω Q) .is-tr = hlevel 1

¬Ω_ : Ω  Ω
¬Ω P = P →Ω ⊥Ω

Furthermore, we can quantify over types of arbitrary size and still land in Ω.

∃Ω :  {} (A : Type )  (A  Ω)  Ω
 ∃Ω A P  =  (Σ[ x  A ]  P x )
∃Ω A P .is-tr = squash

∀Ω :  {} (A : Type )  (A  Ω)  Ω
 ∀Ω A P  =  (∀ (x : A)   P x )
∀Ω A P .is-tr = squash

syntax ∃Ω A  x  B) = ∃Ω[ x  A ] B
syntax ∀Ω A  x  B) = ∀Ω[ x  A ] B

These connectives and quantifiers are only provided for completeness; if you find yourself building nested propositions, it is generally a good idea to construct the large proposition by hand, and then use truncation to turn it into a small proposition.