Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
f o (funb : B => (center {a : A & f a = b}).1) ==
idmap
A, B: Type f: A -> B H: IsTruncMap (-2) f b: B
f (center {a : A & f a = b}).1 = b
exact (center {a : A & f a = b}).2.
A, B: Type f: A -> B H: IsTruncMap (-2) f
(funb : B => (center {a : A & f a = b}).1) o f ==
idmap
A, B: Type f: A -> B H: IsTruncMap (-2) f a: A
(center {a0 : A & f a0 = f a}).1 = a
exact (@contr {x : A & f x = f a} _ (a;1))..1.
A, B: Type f: A -> B H: IsTruncMap (-2) f
forallx : A,
((funb : B => (center {a : A & f a = b}).2)
:
f o (funb : B => (center {a : A & f a = b}).1) ==
idmap) (f x) =
ap f
(((funa : A => (contr (a; 1)) ..1)
:
(funb : B => (center {a : A & f a = b}).1) o f ==
idmap) x)
A, B: Type f: A -> B H: IsTruncMap (-2) f a: A
(center {a0 : A & f a0 = f a}).2 =
ap f (contr (a; 1)) ..1
A, B: Type f: A -> B H: IsTruncMap (-2) f a: A
(ap f (contr (a; 1)) ..1)^ @
(center {a0 : A & f a0 = f a}).2 = 1
A, B: Type f: A -> B H: IsTruncMap (-2) f a: A
transport (funx : B => x = f a)
(ap f (contr (a; 1)) ..1)
(center {a0 : A & f a0 = f a}).2 = 1
A, B: Type f: A -> B H: IsTruncMap (-2) f a: A
transport (funx : A => f x = f a) (contr (a; 1)) ..1
(center {a0 : A & f a0 = f a}).2 = 1
exact ((@contr {x : A & f x = f a} _ (a;1))..2).Defined.(** As usual, we can't make both of these [Instances]. *)#[export] Hint Immediate isequiv_contr_map : typeclass_instances.(** It follows that when proving a map is an equivalence, we may assume its codomain is inhabited. *)
A, B: Type f: A -> B feq: B -> IsEquiv f
IsEquiv f
A, B: Type f: A -> B feq: B -> IsEquiv f
IsEquiv f
A, B: Type f: A -> B feq: B -> IsEquiv f
IsTruncMap (-2) f
A, B: Type f: A -> B feq: B -> IsEquiv f b: B
Contr (hfiber f b)
pose (feq b); exact _.Defined.(** If [functor_sigma idmap g] is an equivalence then so is g. *)
A: Type P, Q: A -> Type g: foralla : A, P a -> Q a IsEquiv0: IsEquiv (functor_sigma idmap g)
foralla : A, IsEquiv (g a)
A: Type P, Q: A -> Type g: foralla : A, P a -> Q a IsEquiv0: IsEquiv (functor_sigma idmap g)
foralla : A, IsEquiv (g a)
A: Type P, Q: A -> Type g: foralla : A, P a -> Q a IsEquiv0: IsEquiv (functor_sigma idmap g) a: A
IsTruncMap (-2) (g a)
A: Type P, Q: A -> Type g: foralla : A, P a -> Q a IsEquiv0: IsEquiv (functor_sigma idmap g) a: A
IsTruncMap (-2) (functor_sigma idmap g)
exact _.Defined.(** Theorem 4.7.7: [functor_sigma idmap g] is an equivalence if and only if g is. *)
A: Type P, Q: A -> Type g: foralla : A, P a -> Q a
A: Type P, Q: A -> Type g: foralla : A, P a -> Q a K: foralla : A, IsEquiv (g a)
IsEquiv (functor_sigma idmap g)
exact isequiv_functor_sigma.Defined.(** ** Assuming [Funext], [IsEquiv f] is an hprop, which has further consequences *)SectionAssumeFunext.Context `{Funext}.
H: Funext A, B: Type f: A -> B H0: IsEquiv f
Contr {g : B -> A & f o g == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f
Contr {g : B -> A & f o g == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f
Contr {g : B -> A & (funx : B => f (g x)) == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f
{g : B -> A & (funx : B => f (g x)) = idmap} <~>
{g : B -> A & (funx : B => f (g x)) == idmap}
(* Typeclass inference finds this contractible instance: it's the fiber over [idmap] of postcomposition with [f], and the latter is an equivalence since [f] is. *)
H: Funext A, B: Type f: A -> B H0: IsEquiv f g: B -> A
(funx : B => f (g x)) = idmap <~>
(funx : B => f (g x)) == idmap
apply equiv_ap10.Defined.
H: Funext A, B: Type f: A -> B H0: IsEquiv f
Contr {g : B -> A & g o f == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f
Contr {g : B -> A & g o f == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f
Contr {g : B -> A & (funx : A => g (f x)) == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f
{g : B -> A & (funx : A => g (f x)) = idmap} <~>
{g : B -> A & (funx : A => g (f x)) == idmap}
H: Funext A, B: Type f: A -> B H0: IsEquiv f g: B -> A
(funx : A => g (f x)) = idmap <~>
(funx : A => g (f x)) == idmap
apply equiv_ap10.Defined.
H: Funext A, B: Type f: A -> B
IsHProp (IsEquiv f)
H: Funext A, B: Type f: A -> B
IsHProp (IsEquiv f)
(* We will show that assuming [f] is an equivalence, [IsEquiv f] decomposes into a sigma of two contractible types. *)
H: Funext A, B: Type f: A -> B feq: IsEquiv f
Contr (IsEquiv f)
H: Funext A, B: Type f: A -> B feq: IsEquiv f
Contr
{ap0
: {a : B -> A & (funx : B => f (a x)) == idmap} &
{s : (funx : A => ap0.1 (f x)) == idmap &
forallx : A, ap0.2 (f x) = ap f (s x)}}
H: Funext A, B: Type f: A -> B feq: IsEquiv f
Contr {a : B -> A & (funx : B => f (a x)) == idmap}
H: Funext A, B: Type f: A -> B feq: IsEquiv f
Contr
((funx : {a : B -> A &
(funx : B => f (a x)) == idmap} =>
{s : (funx0 : A => x.1 (f x0)) == idmap &
forallx0 : A, x.2 (f x0) = ap f (s x0)})
(center
{a : B -> A & (funx : B => f (a x)) == idmap}))
(* Each of these types is equivalent to a based homotopy space. The first is exactly [contr_sect_equiv]. *)
H: Funext A, B: Type f: A -> B feq: IsEquiv f
Contr
((funx : {a : B -> A &
(funx : B => f (a x)) == idmap} =>
{s : (funx0 : A => x.1 (f x0)) == idmap &
forallx0 : A, x.2 (f x0) = ap f (s x0)})
(center
{a : B -> A & (funx : B => f (a x)) == idmap}))
(* The second requires a bit more work. *)
H: Funext A, B: Type f: A -> B feq: IsEquiv f
Contr
{s : (funx : A => f^-1 (f x)) == idmap &
forallx : A, eisretr f (f x) = ap f (s x)}
H: Funext A, B: Type f: A -> B feq: IsEquiv f
{s : (funx : A => f^-1 (f x)) == idmap &
eissect f == s} <~>
{s : (funx : A => f^-1 (f x)) == idmap &
forallx : A, eisretr f (f x) = ap f (s x)}
H: Funext A, B: Type f: A -> B feq: IsEquiv f s: (funx : A => f^-1 (f x)) == idmap
eissect f == s <~>
(forallx : A, eisretr f (f x) = ap f (s x))
H: Funext A, B: Type f: A -> B feq: IsEquiv f s: (funx : A => f^-1 (f x)) == idmap a: A
eissect f a = s a <~> eisretr f (f a) = ap f (s a)
H: Funext A, B: Type f: A -> B feq: IsEquiv f s: (funx : A => f^-1 (f x)) == idmap a: A
eissect f a = s a <~> ap f (eissect f a) = ap f (s a)
rapply equiv_ap.Qed.(** Now since [IsEquiv f] and the assertion that its fibers are contractible are both HProps, logical equivalence implies equivalence. *)
H: Funext A, B: Type f: A -> B
IsTruncMap (-2) f <~> IsEquiv f
H: Funext A, B: Type f: A -> B
IsTruncMap (-2) f <~> IsEquiv f
rapply equiv_iff_hprop.(** Both directions are found by typeclass inference! *)Defined.(** It also follows that paths of equivalences are equivalent to paths of functions. *)
H: Funext A, B: Type e1, e2: A <~> B
e1 = e2 <~> e1 = e2
H: Funext A, B: Type e1, e2: A <~> B
e1 = e2 <~> e1 = e2
H: Funext A, B: Type e1, e2: A <~> B
e1 = e2 <~>
(issig_equiv A B)^-1 e1 = (issig_equiv A B)^-1 e2
H: Funext A, B: Type e1, e2: A <~> B
(issig_equiv A B)^-1 e1 = (issig_equiv A B)^-1 e2 <~>
e1 = e2
H: Funext A, B: Type e1, e2: A <~> B
e1 = e2 <~>
(issig_equiv A B)^-1 e1 = (issig_equiv A B)^-1 e2
exact (equiv_path_sigma_hprop ((issig_equiv A B)^-1 e1) ((issig_equiv A B)^-1 e2)).Defined.Definitionpath_equiv {AB : Type} {e1e2 : A <~> B}
: (e1 = e2 :> (A -> B)) -> (e1 = e2 :> (A <~> B))
:= equiv_path_equiv e1 e2.#[export] Instanceisequiv_path_equiv {AB : Type} {e1e2 : A <~> B}
: IsEquiv (@path_equiv _ _ e1 e2)
(* Coq can find this instance by itself, but it's slow. *)
:= equiv_isequiv (equiv_path_equiv e1 e2).(** The inverse equivalence is homotopic to [ap equiv_fun], so that is also an equivalence. *)
H: Funext A, B: Type e1, e2: A <~> B
IsEquiv (ap equiv_fun)
H: Funext A, B: Type e1, e2: A <~> B
IsEquiv (ap equiv_fun)
H: Funext A, B: Type e1, e2: A <~> B
e1 = e2 -> e1 = e2
H: Funext A, B: Type e1, e2: A <~> B
IsEquiv ?f
H: Funext A, B: Type e1, e2: A <~> B
?f == ap equiv_fun
H: Funext A, B: Type e1, e2: A <~> B
e1 = e2 -> e1 = e2
exact (equiv_path_equiv e1 e2)^-1%equiv.
H: Funext A, B: Type e1, e2: A <~> B
IsEquiv (equiv_path_equiv e1 e2)^-1%equiv
exact _.
H: Funext A, B: Type e1, e2: A <~> B
(equiv_path_equiv e1 e2)^-1%equiv == ap equiv_fun
H: Funext A, B: Type e1, e2: A <~> B p: e1 = e2
(equiv_path_equiv e1 e2)^-1%equiv p = ap equiv_fun p
exact (ap_compose (funv => (equiv_fun v; equiv_isequiv v)) pr1 p)^.Defined.(** This implies that types of equivalences inherit truncation. Note that we only state the theorem for [n.+1]-truncatedness, since it is not true for contractibility: if [B] is contractible but [A] is not, then [A <~> B] is not contractible because it is not inhabited. Don't confuse this lemma with [trunc_equiv], which says that if [A] is truncated and [A] is equivalent to [B], then [B] is truncated. It would be nice to find a better pair of names for them. *)
H: Funext n: trunc_index A, B: Type IsTrunc0: IsTrunc n.+1 B
IsTrunc n.+1 (A <~> B)
H: Funext n: trunc_index A, B: Type IsTrunc0: IsTrunc n.+1 B
IsTrunc n.+1 (A <~> B)
H: Funext n: trunc_index A, B: Type IsTrunc0: IsTrunc n.+1 B
forallxy : A <~> B, IsTrunc n (x = y)
H: Funext n: trunc_index A, B: Type IsTrunc0: IsTrunc n.+1 B e1, e2: A <~> B
IsTrunc n (e1 = e2)
exact (istrunc_equiv_istrunc _ (equiv_path_equiv e1 e2)).Defined.(** In the contractible case, we have to assume that *both* types are contractible to get a contractible type of equivalences. *)
H: Funext A, B: Type Contr0: Contr A Contr1: Contr B
Contr (A <~> B)
H: Funext A, B: Type Contr0: Contr A Contr1: Contr B
Contr (A <~> B)
H: Funext A, B: Type Contr0: Contr A Contr1: Contr B
forally : A <~> B, equiv_contr_contr = y
H: Funext A, B: Type Contr0: Contr A Contr1: Contr B e: A <~> B
equiv_contr_contr = e
H: Funext A, B: Type Contr0: Contr A Contr1: Contr B e: A <~> B
equiv_contr_contr == e
intros ?; apply contr.Defined.(** The type of *automorphisms* of an hprop is always contractible *)
H: Funext A: Type IsHProp0: IsHProp A
Contr (A <~> A)
H: Funext A: Type IsHProp0: IsHProp A
Contr (A <~> A)
H: Funext A: Type IsHProp0: IsHProp A
forally : A <~> A, 1%equiv = y
H: Funext A: Type IsHProp0: IsHProp A e: A <~> A
1%equiv == e
intros ?; apply path_ishprop.Defined.(** Equivalences are functorial under equivalences. *)Definitionfunctor_equiv {ABCD} (h : A <~> C) (k : B <~> D)
: (A <~> B) -> (C <~> D)
:= funf => ((k oE f) oE h^-1).
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D
IsEquiv (functor_equiv h k)
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D
IsEquiv (functor_equiv h k)
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D
(funx : C <~> D =>
functor_equiv h k (functor_equiv h^-1 k^-1 x)) ==
idmap
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D
(funx : A <~> B =>
functor_equiv h^-1 k^-1 (functor_equiv h k x)) ==
idmap
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D
(funx : C <~> D =>
functor_equiv h k (functor_equiv h^-1 k^-1 x)) ==
idmap
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D f: C <~> D x: C
k (k^-1 (f (h (h^-1 x)))) = f x
exact (eisretr k _ @ ap f (eisretr h x)).
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D
(funx : A <~> B =>
functor_equiv h^-1 k^-1 (functor_equiv h k x)) ==
idmap
H: Funext A, B, C, D: Type h: A <~> C k: B <~> D g: A <~> B x: A
k^-1 (k (g (h^-1 (h x)))) = g x
exact (eissect k _ @ ap g (eissect h x)).Defined.Definitionequiv_functor_equiv {ABCD} (h : A <~> C) (k : B <~> D)
: (A <~> B) <~> (C <~> D)
:= Build_Equiv _ _ (functor_equiv h k) _.Definitionequiv_functor_precompose_equiv@{i j k u v | i <= u, j <= v, k <= u, k <= v}
{X : Type@{i}} {Y : Type@{j}} (Z : Type@{k}) (e : X <~> Y)
: Equiv@{v u} (Y <~> Z) (X <~> Z)
:= equiv_functor_equiv e^-1%equiv 1%equiv.Definitionequiv_functor_postcompose_equiv@{i j k u v | i <= u, j <= v, k <= u, k <= v}
{X : Type@{i}} {Y : Type@{j}} (Z : Type@{k}) (e : X <~> Y)
: Equiv@{u v} (Z <~> X) (Z <~> Y)
:= equiv_functor_equiv 1%equiv e.(** Reversing equivalences is an equivalence *)
H: Funext A, B: Type
IsEquiv equiv_inverse
H: Funext A, B: Type
IsEquiv equiv_inverse
refine (isequiv_adjointify _ equiv_inverse _ _);
intros e; apply path_equiv; reflexivity.Defined.Definitionequiv_equiv_inverseAB
: (A <~> B) <~> (B <~> A)
:= Build_Equiv _ _ (@equiv_inverse A B) _.EndAssumeFunext.(** ** Other facts about equivalences *)(** This is like [transport_arrow], but for a family of equivalence types. It just shows that the functions are homotopic. *)
A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1 y: B x2
transport (funx : A => B x <~> C x) p f y =
transport C p (f (transport B p^ y))
A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1 y: B x2
transport (funx : A => B x <~> C x) p f y =
transport C p (f (transport B p^ y))
destruct p; auto.Defined.(** A version that shows that the underlying functions are equal. *)
A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1
transport (funx : A => B x <~> C x) p f =
equiv_transport C p oE f oE equiv_transport B p^
A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1
transport (funx : A => B x <~> C x) p f =
equiv_transport C p oE f oE equiv_transport B p^
destruct p; auto.Defined.(** A version that shows that the equivalences are equal. Here we do need [Funext], for [path_equiv]. *)
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1
transport (funx : A => B x <~> C x) p f =
equiv_transport C p oE f oE equiv_transport B p^
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1
transport (funx : A => B x <~> C x) p f =
equiv_transport C p oE f oE equiv_transport B p^
H: Funext A: Type B, C: A -> Type x1, x2: A p: x1 = x2 f: B x1 <~> C x1
transport (funx : A => B x <~> C x) p f =
equiv_transport C p oE f oE equiv_transport B p^