Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
cubical/Cubical/Foundations/Univalence.agda
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
322 lines (255 sloc)
14.2 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
Proof of the standard formulation of the univalence theorem and | |
various consequences of univalence | |
- Re-exports Glue types from Cubical.Core.Glue | |
- The ua constant and its computation rule (up to a path) | |
- Proof of univalence using that unglue is an equivalence ([EquivContr]) | |
- Equivalence induction ([EquivJ], [elimEquiv]) | |
- Univalence theorem ([univalence]) | |
- The computation rule for ua ([uaβ]) | |
- Isomorphism induction ([elimIso]) | |
-} | |
{-# OPTIONS --safe #-} | |
module Cubical.Foundations.Univalence where | |
open import Cubical.Foundations.Prelude | |
open import Cubical.Foundations.Function | |
open import Cubical.Foundations.Isomorphism | |
open import Cubical.Foundations.Equiv | |
open import Cubical.Foundations.GroupoidLaws | |
open import Cubical.Data.Sigma.Base | |
open import Cubical.Core.Glue public | |
using (Glue ; glue ; unglue) | |
open import Cubical.Reflection.StrictEquiv | |
private | |
variable | |
ℓ ℓ' : Level | |
-- The ua constant | |
ua : ∀ {A B : Type ℓ} → A ≃ B → A ≡ B | |
ua {A = A} {B = B} e i = Glue B (λ { (i = i0) → (A , e) | |
; (i = i1) → (B , idEquiv B) }) | |
uaIdEquiv : {A : Type ℓ} → ua (idEquiv A) ≡ refl | |
uaIdEquiv {A = A} i j = Glue A {φ = i ∨ ~ j ∨ j} (λ _ → A , idEquiv A) | |
-- Propositional extensionality | |
hPropExt : {A B : Type ℓ} → isProp A → isProp B → (A → B) → (B → A) → A ≡ B | |
hPropExt Aprop Bprop f g = ua (propBiimpl→Equiv Aprop Bprop f g) | |
-- the unglue and glue primitives specialized to the case of ua | |
ua-unglue : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : ua e i) | |
→ B {- [ _ ↦ (λ { (i = i0) → e .fst x ; (i = i1) → x }) ] -} | |
ua-unglue e i x = unglue (i ∨ ~ i) x | |
ua-glue : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : Partial (~ i) A) | |
(y : B [ _ ↦ (λ { (i = i0) → e .fst (x 1=1) }) ]) | |
→ ua e i {- [ _ ↦ (λ { (i = i0) → x 1=1 ; (i = i1) → outS y }) ] -} | |
ua-glue e i x y = glue {φ = i ∨ ~ i} (λ { (i = i0) → x 1=1 ; (i = i1) → outS y }) (outS y) | |
module _ {A B : Type ℓ} (e : A ≃ B) {x : A} {y : B} where | |
-- sometimes more useful are versions of these functions with the (i : I) factored in | |
ua-ungluePath : PathP (λ i → ua e i) x y → e .fst x ≡ y | |
ua-ungluePath p i = ua-unglue e i (p i) | |
ua-gluePath : e .fst x ≡ y → PathP (λ i → ua e i) x y | |
ua-gluePath p i = ua-glue e i (λ { (i = i0) → x }) (inS (p i)) | |
-- ua-ungluePath and ua-gluePath are definitional inverses | |
ua-ungluePath-Equiv : (PathP (λ i → ua e i) x y) ≃ (e .fst x ≡ y) | |
unquoteDef ua-ungluePath-Equiv = | |
defStrictEquiv ua-ungluePath-Equiv ua-ungluePath ua-gluePath | |
-- ua-unglue and ua-glue are also definitional inverses, in a way | |
-- strengthening the types of ua-unglue and ua-glue gives a nicer formulation of this, see below | |
ua-unglue-glue : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : Partial (~ i) A) (y : B [ _ ↦ _ ]) | |
→ ua-unglue e i (ua-glue e i x y) ≡ outS y | |
ua-unglue-glue _ _ _ _ = refl | |
ua-glue-unglue : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : ua e i) | |
→ ua-glue e i (λ { (i = i0) → x }) (inS (ua-unglue e i x)) ≡ x | |
ua-glue-unglue _ _ _ = refl | |
-- mainly for documentation purposes, ua-unglue and ua-glue wrapped in cubical subtypes | |
ua-unglueS : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : A) (y : B) | |
→ ua e i [ _ ↦ (λ { (i = i0) → x ; (i = i1) → y }) ] | |
→ B [ _ ↦ (λ { (i = i0) → e .fst x ; (i = i1) → y }) ] | |
ua-unglueS e i x y s = inS (ua-unglue e i (outS s)) | |
ua-glueS : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : A) (y : B) | |
→ B [ _ ↦ (λ { (i = i0) → e .fst x ; (i = i1) → y }) ] | |
→ ua e i [ _ ↦ (λ { (i = i0) → x ; (i = i1) → y }) ] | |
ua-glueS e i x y s = inS (ua-glue e i (λ { (i = i0) → x }) (inS (outS s))) | |
ua-unglueS-glueS : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : A) (y : B) | |
(s : B [ _ ↦ (λ { (i = i0) → e .fst x ; (i = i1) → y }) ]) | |
→ outS (ua-unglueS e i x y (ua-glueS e i x y s)) ≡ outS s | |
ua-unglueS-glueS _ _ _ _ _ = refl | |
ua-glueS-unglueS : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : A) (y : B) | |
(s : ua e i [ _ ↦ (λ { (i = i0) → x ; (i = i1) → y }) ]) | |
→ outS (ua-glueS e i x y (ua-unglueS e i x y s)) ≡ outS s | |
ua-glueS-unglueS _ _ _ _ _ = refl | |
-- a version of ua-glue with a single endpoint, identical to `ua-gluePath e {x} refl i` | |
ua-gluePt : ∀ {A B : Type ℓ} (e : A ≃ B) (i : I) (x : A) | |
→ ua e i {- [ _ ↦ (λ { (i = i0) → x ; (i = i1) → e .fst x }) ] -} | |
ua-gluePt e i x = ua-glue e i (λ { (i = i0) → x }) (inS (e .fst x)) | |
-- Proof of univalence using that unglue is an equivalence: | |
-- unglue is an equivalence | |
unglueIsEquiv : ∀ (A : Type ℓ) (φ : I) | |
(f : PartialP φ (λ o → Σ[ T ∈ Type ℓ ] T ≃ A)) → | |
isEquiv {A = Glue A f} (unglue φ) | |
equiv-proof (unglueIsEquiv A φ f) = λ (b : A) → | |
let u : I → Partial φ A | |
u i = λ{ (φ = i1) → equivCtr (f 1=1 .snd) b .snd (~ i) } | |
ctr : fiber (unglue φ) b | |
ctr = ( glue (λ { (φ = i1) → equivCtr (f 1=1 .snd) b .fst }) (hcomp u b) | |
, λ j → hfill u (inS b) (~ j)) | |
in ( ctr | |
, λ (v : fiber (unglue φ) b) i → | |
let u' : I → Partial (φ ∨ ~ i ∨ i) A | |
u' j = λ { (φ = i1) → equivCtrPath (f 1=1 .snd) b v i .snd (~ j) | |
; (i = i0) → hfill u (inS b) j | |
; (i = i1) → v .snd (~ j) } | |
in ( glue (λ { (φ = i1) → equivCtrPath (f 1=1 .snd) b v i .fst }) (hcomp u' b) | |
, λ j → hfill u' (inS b) (~ j))) | |
-- Any partial family of equivalences can be extended to a total one | |
-- from Glue [ φ ↦ (T,f) ] A to A | |
unglueEquiv : ∀ (A : Type ℓ) (φ : I) | |
(f : PartialP φ (λ o → Σ[ T ∈ Type ℓ ] T ≃ A)) → | |
(Glue A f) ≃ A | |
unglueEquiv A φ f = ( unglue φ , unglueIsEquiv A φ f ) | |
-- The following is a formulation of univalence proposed by Martín Escardó: | |
-- https://groups.google.com/forum/#!msg/homotopytypetheory/HfCB_b-PNEU/Ibb48LvUMeUJ | |
-- See also Theorem 5.8.4 of the HoTT Book. | |
-- | |
-- The reason we have this formulation in the core library and not the | |
-- standard one is that this one is more direct to prove using that | |
-- unglue is an equivalence. The standard formulation can be found in | |
-- Cubical/Basics/Univalence. | |
-- | |
EquivContr : ∀ (A : Type ℓ) → ∃![ T ∈ Type ℓ ] (T ≃ A) | |
EquivContr {ℓ = ℓ} A = | |
( (A , idEquiv A) | |
, idEquiv≡ ) | |
where | |
idEquiv≡ : (y : Σ (Type ℓ) (λ T → T ≃ A)) → (A , idEquiv A) ≡ y | |
idEquiv≡ w = \ { i .fst → Glue A (f i) | |
; i .snd .fst → unglueEquiv _ _ (f i) .fst | |
; i .snd .snd .equiv-proof → unglueEquiv _ _ (f i) .snd .equiv-proof | |
} | |
where | |
f : ∀ i → PartialP (~ i ∨ i) (λ x → Σ[ T ∈ Type ℓ ] T ≃ A) | |
f i = λ { (i = i0) → A , idEquiv A ; (i = i1) → w } | |
contrSinglEquiv : {A B : Type ℓ} (e : A ≃ B) → (B , idEquiv B) ≡ (A , e) | |
contrSinglEquiv {A = A} {B = B} e = | |
isContr→isProp (EquivContr B) (B , idEquiv B) (A , e) | |
-- Equivalence induction | |
EquivJ : {A B : Type ℓ} (P : (A : Type ℓ) → (e : A ≃ B) → Type ℓ') | |
→ (r : P B (idEquiv B)) → (e : A ≃ B) → P A e | |
EquivJ P r e = subst (λ x → P (x .fst) (x .snd)) (contrSinglEquiv e) r | |
-- Assuming that we have an inverse to ua we can easily prove univalence | |
module Univalence (au : ∀ {ℓ} {A B : Type ℓ} → A ≡ B → A ≃ B) | |
(aurefl : ∀ {ℓ} {A : Type ℓ} → au refl ≡ idEquiv A) where | |
ua-au : {A B : Type ℓ} (p : A ≡ B) → ua (au p) ≡ p | |
ua-au {B = B} = J (λ _ p → ua (au p) ≡ p) | |
(cong ua aurefl ∙ uaIdEquiv) | |
au-ua : {A B : Type ℓ} (e : A ≃ B) → au (ua e) ≡ e | |
au-ua {B = B} = EquivJ (λ _ f → au (ua f) ≡ f) | |
(subst (λ r → au r ≡ idEquiv _) (sym uaIdEquiv) aurefl) | |
isoThm : ∀ {ℓ} {A B : Type ℓ} → Iso (A ≡ B) (A ≃ B) | |
isoThm .Iso.fun = au | |
isoThm .Iso.inv = ua | |
isoThm .Iso.rightInv = au-ua | |
isoThm .Iso.leftInv = ua-au | |
thm : ∀ {ℓ} {A B : Type ℓ} → isEquiv au | |
thm {A = A} {B = B} = isoToIsEquiv {B = A ≃ B} isoThm | |
isEquivTransport : {A B : Type ℓ} (p : A ≡ B) → isEquiv (transport p) | |
isEquivTransport p = | |
transport (λ i → isEquiv (transp (λ j → p (i ∧ j)) (~ i))) (idIsEquiv _) | |
pathToEquiv : {A B : Type ℓ} → A ≡ B → A ≃ B | |
pathToEquiv p .fst = transport p | |
pathToEquiv p .snd = isEquivTransport p | |
pathToEquivRefl : {A : Type ℓ} → pathToEquiv refl ≡ idEquiv A | |
pathToEquivRefl {A = A} = equivEq (λ i x → transp (λ _ → A) i x) | |
pathToEquiv-ua : {A B : Type ℓ} (e : A ≃ B) → pathToEquiv (ua e) ≡ e | |
pathToEquiv-ua = Univalence.au-ua pathToEquiv pathToEquivRefl | |
ua-pathToEquiv : {A B : Type ℓ} (p : A ≡ B) → ua (pathToEquiv p) ≡ p | |
ua-pathToEquiv = Univalence.ua-au pathToEquiv pathToEquivRefl | |
-- Univalence | |
univalenceIso : {A B : Type ℓ} → Iso (A ≡ B) (A ≃ B) | |
univalenceIso = Univalence.isoThm pathToEquiv pathToEquivRefl | |
univalence : {A B : Type ℓ} → (A ≡ B) ≃ (A ≃ B) | |
univalence = ( pathToEquiv , Univalence.thm pathToEquiv pathToEquivRefl ) | |
-- The original map from UniMath/Foundations | |
eqweqmap : {A B : Type ℓ} → A ≡ B → A ≃ B | |
eqweqmap {A = A} e = J (λ X _ → A ≃ X) (idEquiv A) e | |
eqweqmapid : {A : Type ℓ} → eqweqmap refl ≡ idEquiv A | |
eqweqmapid {A = A} = JRefl (λ X _ → A ≃ X) (idEquiv A) | |
univalenceStatement : {A B : Type ℓ} → isEquiv (eqweqmap {ℓ} {A} {B}) | |
univalenceStatement = Univalence.thm eqweqmap eqweqmapid | |
univalenceUAH : {A B : Type ℓ} → (A ≡ B) ≃ (A ≃ B) | |
univalenceUAH = ( _ , univalenceStatement ) | |
univalencePath : {A B : Type ℓ} → (A ≡ B) ≡ Lift (A ≃ B) | |
univalencePath = ua (compEquiv univalence LiftEquiv) | |
-- The computation rule for ua. Because of "ghcomp" it is now very | |
-- simple compared to cubicaltt: | |
-- https://github.com/mortberg/cubicaltt/blob/master/examples/univalence.ctt#L202 | |
uaβ : {A B : Type ℓ} (e : A ≃ B) (x : A) → transport (ua e) x ≡ equivFun e x | |
uaβ e x = transportRefl (equivFun e x) | |
uaη : ∀ {A B : Type ℓ} → (P : A ≡ B) → ua (pathToEquiv P) ≡ P | |
uaη = J (λ _ q → ua (pathToEquiv q) ≡ q) (cong ua pathToEquivRefl ∙ uaIdEquiv) | |
-- Lemmas for constructing and destructing dependent paths in a function type where the domain is ua. | |
ua→ : ∀ {ℓ ℓ'} {A₀ A₁ : Type ℓ} {e : A₀ ≃ A₁} {B : (i : I) → Type ℓ'} | |
{f₀ : A₀ → B i0} {f₁ : A₁ → B i1} | |
→ ((a : A₀) → PathP B (f₀ a) (f₁ (e .fst a))) | |
→ PathP (λ i → ua e i → B i) f₀ f₁ | |
ua→ {e = e} {f₀ = f₀} {f₁} h i a = | |
hcomp | |
(λ j → λ | |
{ (i = i0) → f₀ a | |
; (i = i1) → f₁ (lem a j) | |
}) | |
(h (transp (λ j → ua e (~ j ∧ i)) (~ i) a) i) | |
where | |
lem : ∀ a₁ → e .fst (transport (sym (ua e)) a₁) ≡ a₁ | |
lem a₁ = secEq e _ ∙ transportRefl _ | |
ua→⁻ : ∀ {ℓ ℓ'} {A₀ A₁ : Type ℓ} {e : A₀ ≃ A₁} {B : (i : I) → Type ℓ'} | |
{f₀ : A₀ → B i0} {f₁ : A₁ → B i1} | |
→ PathP (λ i → ua e i → B i) f₀ f₁ | |
→ ((a : A₀) → PathP B (f₀ a) (f₁ (e .fst a))) | |
ua→⁻ {e = e} {f₀ = f₀} {f₁} p a i = | |
hcomp | |
(λ k → λ | |
{ (i = i0) → f₀ a | |
; (i = i1) → f₁ (uaβ e a k) | |
}) | |
(p i (transp (λ j → ua e (j ∧ i)) (~ i) a)) | |
ua→2 : ∀ {ℓ ℓ' ℓ''} {A₀ A₁ : Type ℓ} {e₁ : A₀ ≃ A₁} | |
{B₀ B₁ : Type ℓ'} {e₂ : B₀ ≃ B₁} | |
{C : (i : I) → Type ℓ''} | |
{f₀ : A₀ → B₀ → C i0} {f₁ : A₁ → B₁ → C i1} | |
→ (∀ a b → PathP C (f₀ a b) (f₁ (e₁ .fst a) (e₂ .fst b))) | |
→ PathP (λ i → ua e₁ i → ua e₂ i → C i) f₀ f₁ | |
ua→2 h = ua→ (ua→ ∘ h) | |
-- Useful lemma for unfolding a transported function over ua | |
-- If we would have regularity this would be refl | |
transportUAop₁ : ∀ {A B : Type ℓ} → (e : A ≃ B) (f : A → A) (x : B) | |
→ transport (λ i → ua e i → ua e i) f x ≡ equivFun e (f (invEq e x)) | |
transportUAop₁ e f x i = transportRefl (equivFun e (f (invEq e (transportRefl x i)))) i | |
-- Binary version | |
transportUAop₂ : ∀ {ℓ} {A B : Type ℓ} → (e : A ≃ B) (f : A → A → A) (x y : B) | |
→ transport (λ i → ua e i → ua e i → ua e i) f x y ≡ | |
equivFun e (f (invEq e x) (invEq e y)) | |
transportUAop₂ e f x y i = | |
transportRefl (equivFun e (f (invEq e (transportRefl x i)) | |
(invEq e (transportRefl y i)))) i | |
-- Alternative version of EquivJ that only requires a predicate on functions | |
elimEquivFun : {A B : Type ℓ} (P : (A : Type ℓ) → (A → B) → Type ℓ') | |
→ (r : P B (idfun B)) → (e : A ≃ B) → P A (e .fst) | |
elimEquivFun P r e = subst (λ x → P (x .fst) (x .snd .fst)) (contrSinglEquiv e) r | |
-- Isomorphism induction | |
elimIso : {B : Type ℓ} → (Q : {A : Type ℓ} → (A → B) → (B → A) → Type ℓ') → | |
(h : Q (idfun B) (idfun B)) → {A : Type ℓ} → | |
(f : A → B) → (g : B → A) → section f g → retract f g → Q f g | |
elimIso {ℓ} {ℓ'} {B} Q h {A} f g sfg rfg = rem1 f g sfg rfg | |
where | |
P : (A : Type ℓ) → (f : A → B) → Type (ℓ-max ℓ' ℓ) | |
P A f = (g : B → A) → section f g → retract f g → Q f g | |
rem : P B (idfun B) | |
rem g sfg rfg = subst (Q (idfun B)) (λ i b → (sfg b) (~ i)) h | |
rem1 : {A : Type ℓ} → (f : A → B) → P A f | |
rem1 f g sfg rfg = elimEquivFun P rem (f , isoToIsEquiv (iso f g sfg rfg)) g sfg rfg | |
uaInvEquiv : ∀ {A B : Type ℓ} → (e : A ≃ B) → ua (invEquiv e) ≡ sym (ua e) | |
uaInvEquiv {B = B} = EquivJ (λ _ e → ua (invEquiv e) ≡ sym (ua e)) | |
(cong ua (invEquivIdEquiv B)) | |
uaCompEquiv : ∀ {A B C : Type ℓ} → (e : A ≃ B) (f : B ≃ C) → ua (compEquiv e f) ≡ ua e ∙ ua f | |
uaCompEquiv {B = B} {C} = EquivJ (λ _ e → (f : B ≃ C) → ua (compEquiv e f) ≡ ua e ∙ ua f) | |
(λ f → cong ua (compEquivIdEquiv f) | |
∙ sym (cong (λ x → x ∙ ua f) uaIdEquiv | |
∙ sym (lUnit (ua f)))) |