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-prop ∣_∣
is-tr 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
: A → □ A
inc : (x y : □ A) → x ≡ y squash
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.
instance
: ∀ {ℓ} {T : Type ℓ} {n} → H-Level (□ T) (suc n)
H-Level-□ = prop-instance squash
H-Level-□
open hlevel-projection
: hlevel-projection (quote Ω.∣_∣)
Ω-hlevel-proj .has-level = quote Ω.is-tr
Ω-hlevel-proj .get-level x = pure (quoteTerm (suc zero))
Ω-hlevel-proj .get-argument (arg _ t ∷ _) = pure t
Ω-hlevel-proj .get-argument _ = typeError [] Ω-hlevel-proj
We can also prove a univalence principle for Ω
:
: {A B : Ω} → (∣ A ∣ → ∣ B ∣) → (∣ B ∣ → ∣ A ∣) → A ≡ B
Ω-ua {A} {B} f g i .∣_∣ = ua (prop-ext! f g) i
Ω-ua {A} {B} f g i .is-tr =
Ω-ua (λ i → is-prop-is-prop {A = ua (prop-ext! f g) i})
is-prop→pathp (A .is-tr) (B .is-tr) i
instance abstract
: ∀ {n} → H-Level Ω (2 + n)
H-Level-Ω = basic-instance 2 $ retract→is-hlevel 2
H-Level-Ω (λ r → el ∣ r ∣ (r .is-tr))
(λ r → el ∣ r ∣ (r .is-tr))
(λ x → Ω-ua (λ x → x) λ x → x)
(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 inc
s, as usual.
: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'}
□-map → (A → B) → □ A → □ B
(inc x) = inc (f x)
□-map f (squash x y i) = squash (□-map f x) (□-map f y) i
□-map f
: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → is-prop B → (A → B) → □ A → B
□-rec (inc x) = f x
□-rec bp f (squash x y i) = bp (□-rec bp f x) (□-rec bp f y) i
□-rec bp f
: ∀ {ℓ} (T : Type ℓ) → Ω
elΩ .∣_∣ = □ T
elΩ T .is-tr = squash elΩ T
□-elim: ∀ {ℓ ℓ'} {A : Type ℓ} {P : □ A → Type ℓ'}
→ (∀ x → is-prop (P x))
→ (∀ x → P (inc x))
→ ∀ x → P x
(inc x) = go x
□-elim pprop go (squash x y i) =
□-elim pprop go (λ i → pprop (squash x y i)) (□-elim pprop go x) (□-elim pprop go y) i
is-prop→pathp
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
= record
Inductive-□ ⦃ i ⦄ { methods = i .Inductive.methods
; from = λ f → □-elim (λ x → hlevel 1) (i .Inductive.from f)
}
: ∀ {ℓ} {A : Type ℓ} → is-prop A → □ A → A
□-out = □-rec ap (λ x → x)
□-out ap
□-out!: ∀ {ℓ} {A : Type ℓ}
→ ⦃ _ : H-Level A 1 ⦄
→ □ A → A
= rec! λ x → x
□-out!
□-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
: ∀ {ℓ} {A : Type ℓ} → is-prop A → □ A ≃ A
□-idempotent = prop-ext squash aprop (□-out aprop) inc
□-idempotent aprop
□-ap: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'}
→ □ (A → B) → □ A → □ B
(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
□-ap
□-bind: ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'}
→ □ A → (A → □ B) → □ B
(inc x) f = f x
□-bind (squash x x' i) f = squash (□-bind x f) (□-bind x' f) i
□-bind
instance
: Map (eff □)
Map-□ .Map.map = □-map
Map-□
: Idiom (eff □)
Idiom-□ .Idiom.pure = inc
Idiom-□ .Idiom._<*>_ = □-ap
Idiom-□
: Bind (eff □)
Bind-□ .Bind._>>=_ = □-bind
Bind-□
is-set→locally-small: ∀ {ℓ} {A : Type ℓ}
→ is-set A
→ is-identity-system {A = A} (λ x y → □ (x ≡ y)) (λ x → inc refl)
.to-path = □-rec (a-set _ _) id
is-set→locally-small a-set .to-path-over p = is-prop→pathp (λ _ → squash) _ _
is-set→locally-small a-set
to-is-true: ∀ {P Q : Ω} ⦃ _ : H-Level ∣ Q ∣ 0 ⦄
→ ∣ P ∣
→ P ≡ Q
= Ω-ua (λ _ → hlevel 0 .centre) (λ _ → prf)
to-is-true prf
: ∀ {ℓ} {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 □-tr
Connectives🔗
The universe of small propositions contains true, false, conjunctions, disjunctions, and implications.
infixr 10 _∧Ω_
infixr 9 _∨Ω_
infixr 8 _→Ω_
: Ω
⊤Ω = ⊤
∣ ⊤Ω ∣ .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 →Ω ⊥Ω ¬Ω P
Furthermore, we can quantify over types of arbitrary size and still
land in Ω
.
: ∀ {ℓ} (A : Type ℓ) → (A → Ω) → Ω
∃Ω = □ (Σ[ x ∈ A ] ∣ P x ∣)
∣ ∃Ω A P ∣ .is-tr = squash
∃Ω A P
: ∀ {ℓ} (A : Type ℓ) → (A → Ω) → Ω
∀Ω = □ (∀ (x : A) → ∣ P x ∣)
∣ ∀Ω A P ∣ .is-tr = squash
∀Ω A P
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.
module _ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} (f : A → B) where
: Type ℓ'
Ω-image = Σ[ b ∈ B ] □ (fibre f b)
Ω-image
: A → Ω-image
Ω-corestriction = f a , inc (a , refl)
Ω-corestriction a
opaque: is-surjective Ω-corestriction
Ω-corestriction-is-surjective = elim! λ y x fx=y → pure (x , Σ-prop-path! fx=y) Ω-corestriction-is-surjective